{
  "openapi": "3.1.0",
  "info": {
    "title": "Service VIN API",
    "version": "1.0.0",
    "summary": "The public REST API for a Service VIN shop.",
    "description": "Read leads, customers, quotes, invoices and jobs; create leads and customers; subscribe to webhooks.\n\nAuthenticate with a shop API key as `Authorization: Bearer svk_live_…`. Mint one under Settings → API keys.\nEvery key is limited to 120 requests per 60 seconds.\n\nLists page by keyset cursor: pass the previous page's `meta.next_cursor` back as `?cursor=`.",
    "contact": {
      "name": "Service VIN",
      "url": "https://servicevin.com/contact"
    }
  },
  "servers": [
    {
      "url": "https://www.servicevin.com",
      "description": "Your Service VIN app origin"
    }
  ],
  "tags": [
    {
      "name": "Account",
      "description": "Confirm which shop a key belongs to."
    },
    {
      "name": "Leads",
      "description": "Read and create. Creating a lead runs the same pipeline as your website form."
    },
    {
      "name": "Customers",
      "description": "Read, search by email or phone, create and update."
    },
    {
      "name": "Vehicles",
      "description": "Read, search by VIN or plate, and create — with VIN decode included."
    },
    {
      "name": "Quotes",
      "description": "Read-only. Quotes are built in the app; the API reports them."
    },
    {
      "name": "Invoices",
      "description": "Read-only. Invoices are issued and collected in the app; the API reports them."
    },
    {
      "name": "Jobs",
      "description": "Read, and move a job between stages. Job creation returns 501 on purpose — the reason is spelled out below."
    },
    {
      "name": "Appointments",
      "description": "Scheduled work in a time window, in diary order, with customer and vehicle inlined."
    },
    {
      "name": "Messages",
      "description": "Read the message log, and text a customer through the shop's compliant send path."
    },
    {
      "name": "Conversations",
      "description": "The inbox: read threads, find what is waiting on a reply, and change one thing about a thread per call."
    },
    {
      "name": "Calls",
      "description": "The phone log, plus signed short-lived links to recordings and voicemail, and the transcripts. Read-only — a recorded call is history."
    },
    {
      "name": "Tasks",
      "description": "The shop's to-do queue, anchored to a thread, a customer, a job and the message it came from. One change per call, and nothing deletes."
    },
    {
      "name": "Phone numbers",
      "description": "The lines this shop sends and receives on, and which of them can actually send."
    },
    {
      "name": "Services & staff",
      "description": "The service menu and the roster — the lists that fill assignment dropdowns."
    },
    {
      "name": "Webhooks",
      "description": "Subscribe a URL to events, list your subscriptions, unsubscribe."
    },
    {
      "name": "OpenAPI spec",
      "description": "The machine-readable version of this page."
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "A shop API key (`svk_live_…`) from Settings → API keys, scoped to one shop. A read-only key calls every GET; operations that write need a full-access key and answer `403 insufficient_scope` otherwise. A key may also carry an expiry, after which it answers `401`."
      }
    }
  },
  "paths": {
    "/api/v1/me": {
      "get": {
        "operationId": "get-me",
        "summary": "Identify the shop behind a key",
        "description": "Returns the shop the presented key unlocks, and what that key may do. This is the credential test — a 200 means the key is live, a 401 means it is wrong, revoked or expired. It exposes nothing the key holder does not already have, and it is the way to check a key's scope and expiry without opening the dashboard.",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The shop this key is scoped to, and the key's own limits.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "shop": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string",
                              "format": "uuid",
                              "description": "The shop's id."
                            },
                            "name": {
                              "type": "string",
                              "description": "The shop's name."
                            }
                          },
                          "required": [
                            "id",
                            "name"
                          ]
                        },
                        "key": {
                          "type": "object",
                          "properties": {
                            "scope": {
                              "type": "string",
                              "enum": [
                                "read",
                                "full"
                              ],
                              "description": "What this key may do. `read` calls every GET; `full` also writes. Fixed when the key is minted."
                            },
                            "expires_at": {
                              "type": [
                                "string",
                                "null"
                              ],
                              "format": "date-time",
                              "description": "When this key stops working, or null when it never does. Always in the future here — an expired key gets a 401 instead of this response."
                            }
                          },
                          "required": [
                            "scope",
                            "expires_at"
                          ]
                        }
                      },
                      "required": [
                        "shop",
                        "key"
                      ]
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": {
                    "shop": {
                      "id": "9b2f1c6e-4a77-4d2b-9f31-0f1c9a8e5d20",
                      "name": "Apex Detailing"
                    },
                    "key": {
                      "scope": "read",
                      "expires_at": null
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/leads": {
      "get": {
        "operationId": "list-leads",
        "summary": "List leads",
        "description": "Every lead in the shop, newest first. Deleted leads are never returned. The `email`, `phone` and `status` filters turn this into a lookup — an unparseable phone matches nothing rather than erroring, because a search finding nothing is a valid answer.",
        "tags": [
          "Leads"
        ],
        "parameters": [
          {
            "name": "email",
            "in": "query",
            "required": false,
            "description": "Exact match, lower-cased before comparing.",
            "schema": {
              "type": "string"
            },
            "example": "jordan@example.com"
          },
          {
            "name": "phone",
            "in": "query",
            "required": false,
            "description": "Normalized to E.164 before comparing, so any common format works.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only leads at this pipeline status.",
            "schema": {
              "type": "string",
              "enum": [
                "new",
                "contacted",
                "qualified",
                "quoted",
                "won",
                "lost",
                "cold"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Rows per page. Values outside 1–100 are clamped; anything unparseable falls back to the default.",
            "schema": {
              "type": "integer",
              "default": 25,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The previous page's `meta.next_cursor`. Opaque — decode nothing, pass it back verbatim.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "A page of leads, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Service VIN's id for the lead."
                          },
                          "name": {
                            "type": "string",
                            "description": "First and last name joined, falling back to the company name, then to `Unnamed lead`."
                          },
                          "email": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "email",
                            "description": "Lowercased on write."
                          },
                          "phone": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Normalized to E.164 on write."
                          },
                          "source": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Whatever the creator declared. Leads created through this API default to `api`."
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "new",
                              "contacted",
                              "qualified",
                              "quoted",
                              "won",
                              "lost",
                              "cold"
                            ],
                            "description": "Pipeline status. Every API-created lead starts at `new`."
                          },
                          "assigned_to": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid",
                            "description": "The staff member who owns the lead — a **user** id, which is the `user_id` from `GET /api/v1/staff`, not that row's `id`."
                          },
                          "next_followup_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time",
                            "description": "When this lead surfaces for follow-up. A fresh lead is set to now."
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time",
                            "description": "When the lead was created."
                          }
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "next_cursor": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Pass back as `?cursor=` for the next page. `null` means this was the last page."
                        }
                      },
                      "required": [
                        "next_cursor"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "6f1c37a2-91b8-4d0e-8a55-2c7e4b1d9f03",
                      "name": "Jordan Reyes",
                      "email": "jordan@example.com",
                      "phone": "+14035550134",
                      "source": "google-ads",
                      "status": "new",
                      "created_at": "2026-07-16T18:03:11.482Z"
                    }
                  ],
                  "meta": {
                    "next_cursor": null
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "The lead query failed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "internal_error"
                          ],
                          "description": "The lead query failed."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "create-lead",
        "summary": "Create a lead",
        "description": "Creates a lead and fires the same `lead.created` pipeline as the website form — automations, follow-up agents and webhooks all run on it. There is no dedupe-merge: create means create, and you get the id back to own your own idempotency.",
        "tags": [
          "Leads"
        ],
        "requestBody": {
          "required": true,
          "description": "The lead to create.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Full name. Split into first and last on the first whitespace run."
                  },
                  "email": {
                    "type": "string",
                    "format": "email",
                    "maxLength": 200,
                    "description": "Lowercased before storing."
                  },
                  "phone": {
                    "type": "string",
                    "maxLength": 40,
                    "description": "Any common format — normalized to E.164 before storing."
                  },
                  "source": {
                    "type": "string",
                    "maxLength": 120,
                    "description": "Default: `api`. Where the lead came from, e.g. `google-ads`. Shows up in lead-source reporting."
                  },
                  "notes": {
                    "type": "string",
                    "maxLength": 2000,
                    "description": "Free text. Lands on the lead's timeline as a note."
                  }
                },
                "required": [
                  "name"
                ]
              },
              "example": {
                "name": "Jordan Reyes",
                "email": "jordan@example.com",
                "phone": "403-555-0134",
                "source": "google-ads",
                "notes": "Wants full-front PPF on a Model Y"
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "The created lead, in the same shape the list returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Service VIN's id for the lead."
                        },
                        "name": {
                          "type": "string",
                          "description": "First and last name joined, falling back to the company name, then to `Unnamed lead`."
                        },
                        "email": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "email",
                          "description": "Lowercased on write."
                        },
                        "phone": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Normalized to E.164 on write."
                        },
                        "source": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Whatever the creator declared. Leads created through this API default to `api`."
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "new",
                            "contacted",
                            "qualified",
                            "quoted",
                            "won",
                            "lost",
                            "cold"
                          ],
                          "description": "Pipeline status. Every API-created lead starts at `new`."
                        },
                        "assigned_to": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The staff member who owns the lead — a **user** id, which is the `user_id` from `GET /api/v1/staff`, not that row's `id`."
                        },
                        "next_followup_at": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "When this lead surfaces for follow-up. A fresh lead is set to now."
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "When the lead was created."
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": {
                    "id": "6f1c37a2-91b8-4d0e-8a55-2c7e4b1d9f03",
                    "name": "Jordan Reyes",
                    "email": "jordan@example.com",
                    "phone": "+14035550134",
                    "source": "google-ads",
                    "status": "new",
                    "created_at": "2026-07-16T18:03:11.482Z"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The body was not valid JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "invalid_request"
                          ],
                          "description": "The body was not valid JSON."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not. The key is read-only and this endpoint writes. Mint a full-access key; the scope is fixed when a key is created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "422": {
            "description": "A field failed validation — the message names it, e.g. `name: name is required`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "validation_error"
                          ],
                          "description": "A field failed validation — the message names it, e.g. `name: name is required`."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "The insert failed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "internal_error"
                          ],
                          "description": "The insert failed."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customers": {
      "get": {
        "operationId": "list-customers",
        "summary": "List or find customers",
        "description": "Every customer in the shop, newest first. Add `email` or `phone` to turn it into an exact-match lookup — the phone is normalized before matching, so any common format finds the record.",
        "tags": [
          "Customers"
        ],
        "parameters": [
          {
            "name": "email",
            "in": "query",
            "required": false,
            "description": "Exact match, case-insensitive.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "phone",
            "in": "query",
            "required": false,
            "description": "Exact match after E.164 normalization. A number that cannot be normalized returns an empty page rather than an error.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Rows per page. Values outside 1–100 are clamped; anything unparseable falls back to the default.",
            "schema": {
              "type": "integer",
              "default": 25,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The previous page's `meta.next_cursor`. Opaque — decode nothing, pass it back verbatim.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "A page of customers, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Service VIN's id for the customer."
                          },
                          "name": {
                            "type": "string",
                            "description": "The customer's display name, or `—` when the record has none."
                          },
                          "email": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "email",
                            "description": "Lowercased on write."
                          },
                          "phone": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Normalized to E.164 on write."
                          },
                          "city": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "City on the customer's address."
                          },
                          "region": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Province or state."
                          },
                          "postal_code": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Postal or ZIP code."
                          },
                          "tags": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            },
                            "description": "Free-form labels the shop applies. Empty array when there are none."
                          },
                          "is_vip": {
                            "type": "boolean",
                            "description": "The shop's own VIP flag."
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time",
                            "description": "When the customer was created."
                          }
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "next_cursor": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Pass back as `?cursor=` for the next page. `null` means this was the last page."
                        }
                      },
                      "required": [
                        "next_cursor"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                      "name": "Jordan Reyes",
                      "email": "jordan@example.com",
                      "phone": "+14035550134",
                      "created_at": "2026-07-16T18:03:11.482Z"
                    }
                  ],
                  "meta": {
                    "next_cursor": null
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "The customer query failed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "internal_error"
                          ],
                          "description": "The customer query failed."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "create-customer",
        "summary": "Create a customer",
        "description": "Creates a customer. A phone or an email is required — a name alone cannot be stored, because a customer nobody can contact is not a customer. If that contact is already on file you get a 409 naming the existing id, rather than a duplicate that would split their money and message history.",
        "tags": [
          "Customers"
        ],
        "requestBody": {
          "required": true,
          "description": "The customer to create. At least one of `email` or `phone` is required.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Full name."
                  },
                  "email": {
                    "type": "string",
                    "format": "email",
                    "maxLength": 200,
                    "description": "Required unless `phone` is sent."
                  },
                  "phone": {
                    "type": "string",
                    "maxLength": 40,
                    "description": "Required unless `email` is sent. Normalized to E.164."
                  },
                  "consent_source": {
                    "type": "string",
                    "enum": [
                      "express_written",
                      "express_verbal",
                      "online_booking",
                      "web_form",
                      "implied_existing_business",
                      "implied_inquiry",
                      "imported",
                      "unknown"
                    ],
                    "description": "Default: `unknown`. How this contact consented to be messaged. Posting a contact is not itself evidence of consent, so this defaults to `unknown` rather than the API inventing a basis. Send it only when you genuinely know."
                  },
                  "consent_captured_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When that consent was captured (ISO 8601 with an offset). Dropped when `consent_source` is `unknown`, so a bare timestamp can never later read as evidence."
                  },
                  "consent_note": {
                    "type": "string",
                    "maxLength": 500,
                    "description": "Free-text provenance, e.g. the form name."
                  }
                },
                "required": [
                  "name"
                ]
              },
              "example": {
                "name": "Jordan Reyes",
                "email": "jordan@example.com",
                "phone": "403-555-0134"
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "The created customer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Service VIN's id for the customer."
                        },
                        "name": {
                          "type": "string",
                          "description": "The customer's display name, or `—` when the record has none."
                        },
                        "email": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "email",
                          "description": "Lowercased on write."
                        },
                        "phone": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Normalized to E.164 on write."
                        },
                        "city": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "City on the customer's address."
                        },
                        "region": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Province or state."
                        },
                        "postal_code": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Postal or ZIP code."
                        },
                        "tags": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Free-form labels the shop applies. Empty array when there are none."
                        },
                        "is_vip": {
                          "type": "boolean",
                          "description": "The shop's own VIP flag."
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "When the customer was created."
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": {
                    "id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                    "name": "Jordan Reyes",
                    "email": "jordan@example.com",
                    "phone": "+14035550134",
                    "created_at": "2026-07-16T18:03:11.482Z"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The body was not valid JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "invalid_request"
                          ],
                          "description": "The body was not valid JSON."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not. The key is read-only and this endpoint writes. Mint a full-access key; the scope is fixed when a key is created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "409": {
            "description": "That email or phone already belongs to a customer. The message carries the existing id.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "conflict"
                          ],
                          "description": "That email or phone already belongs to a customer. The message carries the existing id."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "422": {
            "description": "A field failed validation, or neither `email` nor `phone` was sent.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "validation_error"
                          ],
                          "description": "A field failed validation, or neither `email` nor `phone` was sent."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "The insert failed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "internal_error"
                          ],
                          "description": "The insert failed."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/quotes": {
      "get": {
        "operationId": "list-quotes",
        "summary": "List quotes",
        "description": "Quotes for the shop, newest first. Read-only: quote lines, taxes and margins are built in the app, and this endpoint reports the outcome.",
        "tags": [
          "Quotes"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Return only quotes in this status. An unrecognised value is a 422, never a silent full list.",
            "schema": {
              "type": "string",
              "enum": [
                "draft",
                "sent",
                "viewed",
                "accepted",
                "declined",
                "expired"
              ]
            },
            "example": "accepted"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Rows per page. Values outside 1–100 are clamped; anything unparseable falls back to the default.",
            "schema": {
              "type": "integer",
              "default": 25,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The previous page's `meta.next_cursor`. Opaque — decode nothing, pass it back verbatim.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "A page of quotes, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Service VIN's id for the quote."
                          },
                          "number": {
                            "type": "integer",
                            "description": "The shop-visible quote number."
                          },
                          "customer_id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "The customer this quote belongs to."
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "draft",
                              "sent",
                              "viewed",
                              "accepted",
                              "declined",
                              "expired"
                            ],
                            "description": "Where the quote stands."
                          },
                          "total": {
                            "type": "number",
                            "description": "Quote total, tax included, in the shop's currency."
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time",
                            "description": "When the quote was created."
                          }
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "next_cursor": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Pass back as `?cursor=` for the next page. `null` means this was the last page."
                        }
                      },
                      "required": [
                        "next_cursor"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "1c8a5f2e-6b74-4d39-a0e1-58c3f7d2b916",
                      "number": 1042,
                      "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                      "status": "accepted",
                      "total": 2899.5,
                      "created_at": "2026-07-16T18:03:11.482Z"
                    }
                  ],
                  "meta": {
                    "next_cursor": null
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "422": {
            "description": "`status` is not one of the listed values.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "validation_error"
                          ],
                          "description": "`status` is not one of the listed values."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "The quote query failed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "internal_error"
                          ],
                          "description": "The quote query failed."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/invoices": {
      "get": {
        "operationId": "list-invoices",
        "summary": "List invoices",
        "description": "Invoices for the shop, newest first, each with a live `balance`. Read-only: invoices are minted and collected in the app, and this endpoint reports them. Lists invoices created in Service VIN; a shop's migrated billing history is behind `?imported=true`.",
        "tags": [
          "Invoices"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Return only invoices in this status. An unrecognised value is a 422.",
            "schema": {
              "type": "string",
              "enum": [
                "draft",
                "open",
                "partial",
                "paid",
                "void",
                "refunded"
              ]
            },
            "example": "open"
          },
          {
            "name": "imported",
            "in": "query",
            "required": false,
            "description": "Return only records that arrived through a data import. Default lists only records created in Service VIN. `1` and `0` are accepted as aliases; any other value is a 422 rather than a silent fallback, because a caller who typos this has been given a wrong answer about which records exist.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "false"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Rows per page. Values outside 1–100 are clamped; anything unparseable falls back to the default.",
            "schema": {
              "type": "integer",
              "default": 25,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The previous page's `meta.next_cursor`. Opaque — decode nothing, pass it back verbatim.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "A page of invoices, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Service VIN's id for the invoice."
                          },
                          "number": {
                            "type": "integer",
                            "description": "The shop-visible invoice number."
                          },
                          "customer_id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "The customer this invoice belongs to."
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "draft",
                              "open",
                              "partial",
                              "paid",
                              "void",
                              "refunded"
                            ],
                            "description": "Where the invoice stands."
                          },
                          "total": {
                            "type": "number",
                            "description": "Invoice total, tax included."
                          },
                          "balance": {
                            "type": [
                              "number",
                              "null"
                            ],
                            "description": "Amount still owing. `0` once the invoice is paid in full."
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time",
                            "description": "When the invoice was created."
                          }
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "next_cursor": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Pass back as `?cursor=` for the next page. `null` means this was the last page."
                        }
                      },
                      "required": [
                        "next_cursor"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "7e3b9d41-0a52-4c8f-b6d7-91f4a2e5c308",
                      "number": 587,
                      "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                      "status": "partial",
                      "total": 2899.5,
                      "balance": 1399.5,
                      "created_at": "2026-07-16T18:03:11.482Z"
                    }
                  ],
                  "meta": {
                    "next_cursor": null
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "422": {
            "description": "`status` is not one of the listed values. `imported` is not `true` or `false` (or their `1`/`0` aliases).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "validation_error"
                          ],
                          "description": "`status` is not one of the listed values."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "The invoice query failed. `imported=true` on a database without migration 0187/0152 — invoices are the one resource whose provenance can be unanswerable, and slicing by it cannot be faked. The default live list still answers, and the request succeeds on retry once the shop applies the migration.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "internal_error"
                          ],
                          "description": "The invoice query failed."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/jobs": {
      "get": {
        "operationId": "list-jobs",
        "summary": "List jobs",
        "description": "Jobs for the shop, newest first. Read-only — see the note under `POST /api/v1/jobs`. Lists work created in Service VIN; jobs carried in by a data import are behind `?imported=true`.",
        "tags": [
          "Jobs"
        ],
        "parameters": [
          {
            "name": "stage",
            "in": "query",
            "required": false,
            "description": "Return only jobs at this stage. An unrecognised value is a 422.",
            "schema": {
              "type": "string",
              "enum": [
                "lead",
                "scheduled",
                "in_progress",
                "curing",
                "qa",
                "ready",
                "completed",
                "canceled"
              ]
            },
            "example": "scheduled"
          },
          {
            "name": "customer_id",
            "in": "query",
            "required": false,
            "description": "Only this customer's jobs — their whole history, newest first. A migrated customer's pre-switch work sits behind `?imported=true` on this same `customer_id`: the provenance rule keys on the record, never on the person.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "imported",
            "in": "query",
            "required": false,
            "description": "Return only records that arrived through a data import. Default lists only records created in Service VIN. `1` and `0` are accepted as aliases; any other value is a 422 rather than a silent fallback, because a caller who typos this has been given a wrong answer about which records exist.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "false"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Rows per page. Values outside 1–100 are clamped; anything unparseable falls back to the default.",
            "schema": {
              "type": "integer",
              "default": 25,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The previous page's `meta.next_cursor`. Opaque — decode nothing, pass it back verbatim.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "A page of jobs, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Service VIN's id for the job."
                          },
                          "number": {
                            "type": "integer",
                            "description": "The shop-visible job number."
                          },
                          "title": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "What the job is, e.g. `Full-front PPF`."
                          },
                          "customer_id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "The customer this job belongs to."
                          },
                          "vehicle_id": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid",
                            "description": "The vehicle being worked on, when one is attached."
                          },
                          "stage": {
                            "type": "string",
                            "enum": [
                              "lead",
                              "scheduled",
                              "in_progress",
                              "curing",
                              "qa",
                              "ready",
                              "completed",
                              "canceled"
                            ],
                            "description": "Where the job sits on the board."
                          },
                          "assignee_id": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid",
                            "description": "Assigned staff — a **staff profile** id, which is the `id` from `GET /api/v1/staff`, not that row's `user_id`."
                          },
                          "scheduled_start": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time",
                            "description": "Booked start, or `null` while the job is unscheduled."
                          },
                          "scheduled_end": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time",
                            "description": "Booked end, or `null` while the job is unscheduled."
                          },
                          "actual_start": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time",
                            "description": "When work really began — stamped the first time the job reaches `in_progress` or beyond, and never cleared by a move backwards."
                          },
                          "actual_end": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time",
                            "description": "When work finished. Re-stamped on every entry into `completed`, and cleared when the job leaves it."
                          },
                          "location_address": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Where the work happens, for mobile jobs."
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time",
                            "description": "When the job was created."
                          }
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "next_cursor": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Pass back as `?cursor=` for the next page. `null` means this was the last page."
                        }
                      },
                      "required": [
                        "next_cursor"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "4a92c7f1-8d36-4b05-9e2a-1f6b3d8c50e7",
                      "number": 317,
                      "title": "Full-front PPF",
                      "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                      "vehicle_id": "0d5e8b31-7f24-4a96-b3c8-e2517da9c064",
                      "stage": "scheduled",
                      "scheduled_start": "2026-07-20T15:00:00.000Z",
                      "scheduled_end": "2026-07-20T21:00:00.000Z",
                      "created_at": "2026-07-16T18:03:11.482Z"
                    }
                  ],
                  "meta": {
                    "next_cursor": null
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "422": {
            "description": "`stage` is not one of the listed values. `imported` is not `true` or `false` (or their `1`/`0` aliases).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "validation_error"
                          ],
                          "description": "`stage` is not one of the listed values."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "The job query failed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "internal_error"
                          ],
                          "description": "The job query failed."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "create-job",
        "summary": "Not offered — always 501",
        "description": "Creating a job is not a bare insert here: it allocates a shop sequence number, verifies the customer, vehicle and bay references, respects the bay double-booking rule, and geocodes mobile jobs. An API insert would skip those and create jobs the scheduler cannot trust, so this endpoint says so instead of guessing. Create a lead with `POST /api/v1/leads` and convert it in the dashboard, or book the job on the calendar.",
        "tags": [
          "Jobs"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not. The key is read-only and this endpoint writes. Mint a full-access key; the scope is fixed when a key is created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "501": {
            "description": "Always. There is no success case. Every request.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object"
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "error": {
                    "code": "not_implemented",
                    "message": "Creating jobs via the API isn't supported yet — book jobs from the Service VIN calendar, or create a lead here and convert it in the app."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/leads/{id}": {
      "get": {
        "operationId": "get-lead",
        "summary": "Get one lead",
        "description": "The same shape the list returns, for one lead.",
        "tags": [
          "Leads"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The lead's id.",
            "schema": {
              "type": "string"
            },
            "example": "6f1c37a2-91b8-4d0e-8a55-2c7e4b1d9f03"
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The lead.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Service VIN's id for the lead."
                        },
                        "name": {
                          "type": "string",
                          "description": "First and last name joined, falling back to the company name, then to `Unnamed lead`."
                        },
                        "email": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "email",
                          "description": "Lowercased on write."
                        },
                        "phone": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Normalized to E.164 on write."
                        },
                        "source": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Whatever the creator declared. Leads created through this API default to `api`."
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "new",
                            "contacted",
                            "qualified",
                            "quoted",
                            "won",
                            "lost",
                            "cold"
                          ],
                          "description": "Pipeline status. Every API-created lead starts at `new`."
                        },
                        "assigned_to": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The staff member who owns the lead — a **user** id, which is the `user_id` from `GET /api/v1/staff`, not that row's `id`."
                        },
                        "next_followup_at": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "When this lead surfaces for follow-up. A fresh lead is set to now."
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "When the lead was created."
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": {
                    "id": "6f1c37a2-91b8-4d0e-8a55-2c7e4b1d9f03",
                    "name": "Jordan Reyes",
                    "email": "jordan@example.com",
                    "phone": "+14035550134",
                    "source": "google-ads",
                    "status": "contacted",
                    "assigned_to": null,
                    "next_followup_at": "2026-07-16T18:03:11.482Z",
                    "created_at": "2026-07-16T18:03:11.482Z"
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No lead with that id in this shop.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "not_found"
                          ],
                          "description": "No lead with that id in this shop."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "update-lead",
        "summary": "Update a lead",
        "description": "Moves a lead through the pipeline. A real status change appends `lead.status_changed` exactly as the dashboard does, so automations and webhooks fire — re-sending the status it already has does not, so a retry cannot double-fire anyone's Zap. Merging a lead or converting it to a customer stays in the app.",
        "tags": [
          "Leads"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The lead's id.",
            "schema": {
              "type": "string"
            },
            "example": "6f1c37a2-91b8-4d0e-8a55-2c7e4b1d9f03"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "At least one field. Anything omitted is left alone.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "new",
                      "contacted",
                      "qualified",
                      "quoted",
                      "won",
                      "lost",
                      "cold"
                    ],
                    "description": "New pipeline status."
                  },
                  "assigned_to": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uuid",
                    "description": "Owner — the `user_id` from `GET /api/v1/staff`, not that row's `id`. Null clears it."
                  },
                  "next_followup_at": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time",
                    "description": "When the lead next surfaces. Null clears it."
                  }
                }
              },
              "example": {
                "status": "qualified"
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The updated lead.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Service VIN's id for the lead."
                        },
                        "name": {
                          "type": "string",
                          "description": "First and last name joined, falling back to the company name, then to `Unnamed lead`."
                        },
                        "email": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "email",
                          "description": "Lowercased on write."
                        },
                        "phone": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Normalized to E.164 on write."
                        },
                        "source": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Whatever the creator declared. Leads created through this API default to `api`."
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "new",
                            "contacted",
                            "qualified",
                            "quoted",
                            "won",
                            "lost",
                            "cold"
                          ],
                          "description": "Pipeline status. Every API-created lead starts at `new`."
                        },
                        "assigned_to": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The staff member who owns the lead — a **user** id, which is the `user_id` from `GET /api/v1/staff`, not that row's `id`."
                        },
                        "next_followup_at": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "When this lead surfaces for follow-up. A fresh lead is set to now."
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "When the lead was created."
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": {
                    "id": "6f1c37a2-91b8-4d0e-8a55-2c7e4b1d9f03",
                    "name": "Jordan Reyes",
                    "email": "jordan@example.com",
                    "phone": "+14035550134",
                    "source": "google-ads",
                    "status": "qualified",
                    "assigned_to": null,
                    "next_followup_at": "2026-07-16T18:03:11.482Z",
                    "created_at": "2026-07-16T18:03:11.482Z"
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not. The key is read-only and this endpoint writes. Mint a full-access key; the scope is fixed when a key is created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No lead with that id in this shop.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "not_found"
                          ],
                          "description": "No lead with that id in this shop."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "422": {
            "description": "The body carried no updatable field, or a field failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "validation_error"
                          ],
                          "description": "The body carried no updatable field, or a field failed validation."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customers/{id}": {
      "get": {
        "operationId": "get-customer",
        "summary": "Get one customer",
        "description": "The same shape the list returns, for one customer.",
        "tags": [
          "Customers"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The customer's id.",
            "schema": {
              "type": "string"
            },
            "example": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48"
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The customer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Service VIN's id for the customer."
                        },
                        "name": {
                          "type": "string",
                          "description": "The customer's display name, or `—` when the record has none."
                        },
                        "email": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "email",
                          "description": "Lowercased on write."
                        },
                        "phone": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Normalized to E.164 on write."
                        },
                        "city": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "City on the customer's address."
                        },
                        "region": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Province or state."
                        },
                        "postal_code": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Postal or ZIP code."
                        },
                        "tags": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Free-form labels the shop applies. Empty array when there are none."
                        },
                        "is_vip": {
                          "type": "boolean",
                          "description": "The shop's own VIP flag."
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "When the customer was created."
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": {
                    "id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                    "name": "Jordan Reyes",
                    "email": "jordan@example.com",
                    "phone": "+14165550134",
                    "city": "Toronto",
                    "region": "ON",
                    "postal_code": "M5V 1J9",
                    "tags": [
                      "ppf"
                    ],
                    "is_vip": false,
                    "created_at": "2026-07-16T18:03:11.482Z"
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No customer with that id in this shop.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "not_found"
                          ],
                          "description": "No customer with that id in this shop."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "update-customer",
        "summary": "Update a customer",
        "description": "Updates contact details. Two guards apply to the MERGED record rather than the patch: a customer can never be left with neither an email nor a phone, and moving a contact onto a value another customer already holds returns 409 with that id instead of splitting one person's history across two records. Merging customers stays in the app.",
        "tags": [
          "Customers"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The customer's id.",
            "schema": {
              "type": "string"
            },
            "example": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "At least one field. Anything omitted is left alone.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Split into first and last."
                  },
                  "email": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "email",
                    "description": "Lowercased. Null clears it."
                  },
                  "phone": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Normalized to E.164. Null clears it."
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Replaces the whole tag list."
                  },
                  "is_vip": {
                    "type": "boolean",
                    "description": "The shop's VIP flag."
                  }
                }
              },
              "example": {
                "tags": [
                  "ppf",
                  "repeat"
                ],
                "is_vip": true
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The updated customer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Service VIN's id for the customer."
                        },
                        "name": {
                          "type": "string",
                          "description": "The customer's display name, or `—` when the record has none."
                        },
                        "email": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "email",
                          "description": "Lowercased on write."
                        },
                        "phone": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Normalized to E.164 on write."
                        },
                        "city": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "City on the customer's address."
                        },
                        "region": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Province or state."
                        },
                        "postal_code": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Postal or ZIP code."
                        },
                        "tags": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Free-form labels the shop applies. Empty array when there are none."
                        },
                        "is_vip": {
                          "type": "boolean",
                          "description": "The shop's own VIP flag."
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "When the customer was created."
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": {
                    "id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                    "name": "Jordan Reyes",
                    "email": "jordan@example.com",
                    "phone": "+14165550134",
                    "city": "Toronto",
                    "region": "ON",
                    "postal_code": "M5V 1J9",
                    "tags": [
                      "ppf",
                      "repeat"
                    ],
                    "is_vip": true,
                    "created_at": "2026-07-16T18:03:11.482Z"
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not. The key is read-only and this endpoint writes. Mint a full-access key; the scope is fixed when a key is created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No customer with that id in this shop.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "not_found"
                          ],
                          "description": "No customer with that id in this shop."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "409": {
            "description": "Another customer already holds the email or phone being moved. The message names the id.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "conflict"
                          ],
                          "description": "Another customer already holds the email or phone being moved. The message names the id."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "422": {
            "description": "The body carried no updatable field, the phone was unparseable, or the change would leave the customer with no contact at all.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "validation_error"
                          ],
                          "description": "The body carried no updatable field, the phone was unparseable, or the change would leave the customer with no contact at all."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/vehicles": {
      "get": {
        "operationId": "list-vehicles",
        "summary": "List vehicles",
        "description": "Vehicles on file, newest first. `vin` is normalized before matching (so a hyphenated VIN still finds its row) and `license_plate` matches case-insensitively, because plates are recorded inconsistently.",
        "tags": [
          "Vehicles"
        ],
        "parameters": [
          {
            "name": "customer_id",
            "in": "query",
            "required": false,
            "description": "Only this customer's vehicles.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "vin",
            "in": "query",
            "required": false,
            "description": "Exact match after normalizing.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "license_plate",
            "in": "query",
            "required": false,
            "description": "Case-insensitive match.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Rows per page. Values outside 1–100 are clamped; anything unparseable falls back to the default.",
            "schema": {
              "type": "integer",
              "default": 25,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The previous page's `meta.next_cursor`. Opaque — decode nothing, pass it back verbatim.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "A page of vehicles, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Service VIN's id for the vehicle."
                          },
                          "customer_id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "The vehicle's owner."
                          },
                          "label": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Year, make, model and trim as one string (`2024 BMW M3`) — for message templates that want the car in a single field."
                          },
                          "year": {
                            "type": [
                              "integer",
                              "null"
                            ],
                            "description": "Model year."
                          },
                          "make": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Manufacturer."
                          },
                          "model": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Model."
                          },
                          "trim": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Trim level."
                          },
                          "color": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Colour as the shop recorded it."
                          },
                          "vin": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "17-character VIN, upper-cased."
                          },
                          "license_plate": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Plate as recorded."
                          },
                          "mileage": {
                            "type": [
                              "integer",
                              "null"
                            ],
                            "description": "Odometer reading when recorded."
                          },
                          "vehicle_type": {
                            "type": "string",
                            "description": "Body category, filled from the VIN decode when one was available."
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time",
                            "description": "When the vehicle was added."
                          }
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "next_cursor": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Pass back as `?cursor=` for the next page. `null` means this was the last page."
                        }
                      },
                      "required": [
                        "next_cursor"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "0d5e8b31-7f24-4a96-b3c8-e2517da9c064",
                      "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                      "label": "2024 BMW M3",
                      "year": 2024,
                      "make": "BMW",
                      "model": "M3",
                      "trim": "Competition",
                      "color": "Black",
                      "vin": "WBS43AY05RFR12345",
                      "license_plate": "ABC 123",
                      "mileage": 4200,
                      "vehicle_type": "car",
                      "created_at": "2026-07-16T18:03:11.482Z"
                    }
                  ],
                  "meta": {
                    "next_cursor": null
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "The vehicle query failed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "internal_error"
                          ],
                          "description": "The vehicle query failed."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "create-vehicle",
        "summary": "Create a vehicle",
        "description": "Adds a vehicle to an existing customer. Sending just `customer_id` and `vin` is enough — the VIN is decoded through the same NHTSA path the app's scanner uses, filling year, make, model and trim. Anything you supply explicitly wins over the decode, and an unreachable decoder yields a vehicle carrying the raw VIN rather than a failed request.",
        "tags": [
          "Vehicles"
        ],
        "requestBody": {
          "required": true,
          "description": "The vehicle. Needs a VIN, or at least a make or model.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "customer_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Must be a customer of this shop."
                  },
                  "vin": {
                    "type": "string",
                    "maxLength": 32,
                    "description": "17 characters, excluding I, O and Q."
                  },
                  "year": {
                    "type": "integer",
                    "description": "Model year."
                  },
                  "make": {
                    "type": "string",
                    "maxLength": 80,
                    "description": "Overrides the decode."
                  },
                  "model": {
                    "type": "string",
                    "maxLength": 80,
                    "description": "Overrides the decode."
                  },
                  "trim": {
                    "type": "string",
                    "maxLength": 80,
                    "description": "Overrides the decode."
                  },
                  "color": {
                    "type": "string",
                    "maxLength": 40,
                    "description": "Colour."
                  },
                  "license_plate": {
                    "type": "string",
                    "maxLength": 20,
                    "description": "Plate."
                  },
                  "mileage": {
                    "type": "integer",
                    "description": "Odometer reading."
                  },
                  "vehicle_type": {
                    "type": "string",
                    "description": "Overrides the decoded body category."
                  }
                },
                "required": [
                  "customer_id"
                ]
              },
              "example": {
                "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                "vin": "WBS43AY05RFR12345"
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "The created vehicle.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Service VIN's id for the vehicle."
                        },
                        "customer_id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "The vehicle's owner."
                        },
                        "label": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Year, make, model and trim as one string (`2024 BMW M3`) — for message templates that want the car in a single field."
                        },
                        "year": {
                          "type": [
                            "integer",
                            "null"
                          ],
                          "description": "Model year."
                        },
                        "make": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Manufacturer."
                        },
                        "model": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Model."
                        },
                        "trim": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Trim level."
                        },
                        "color": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Colour as the shop recorded it."
                        },
                        "vin": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "17-character VIN, upper-cased."
                        },
                        "license_plate": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Plate as recorded."
                        },
                        "mileage": {
                          "type": [
                            "integer",
                            "null"
                          ],
                          "description": "Odometer reading when recorded."
                        },
                        "vehicle_type": {
                          "type": "string",
                          "description": "Body category, filled from the VIN decode when one was available."
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "When the vehicle was added."
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": {
                    "id": "0d5e8b31-7f24-4a96-b3c8-e2517da9c064",
                    "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                    "label": "2024 BMW M3",
                    "year": 2024,
                    "make": "BMW",
                    "model": "M3",
                    "trim": "Competition",
                    "color": null,
                    "vin": "WBS43AY05RFR12345",
                    "license_plate": null,
                    "mileage": null,
                    "vehicle_type": "car",
                    "created_at": "2026-07-16T18:03:11.482Z"
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not. The key is read-only and this endpoint writes. Mint a full-access key; the scope is fixed when a key is created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No customer with that id in this shop.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "not_found"
                          ],
                          "description": "No customer with that id in this shop."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "409": {
            "description": "That VIN is already on file for this shop. The message names the existing vehicle id.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "conflict"
                          ],
                          "description": "That VIN is already on file for this shop. The message names the existing vehicle id."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "422": {
            "description": "The VIN was malformed, or the body carried neither a VIN nor a make or model.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "validation_error"
                          ],
                          "description": "The VIN was malformed, or the body carried neither a VIN nor a make or model."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/jobs/{id}": {
      "get": {
        "operationId": "get-job",
        "summary": "Get one job",
        "description": "The same shape the list returns, for one job.",
        "tags": [
          "Jobs"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The job's id.",
            "schema": {
              "type": "string"
            },
            "example": "4a92c7f1-8d36-4b05-9e2a-1f6b3d8c50e7"
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The job.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Service VIN's id for the job."
                        },
                        "number": {
                          "type": "integer",
                          "description": "The shop-visible job number."
                        },
                        "title": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "What the job is, e.g. `Full-front PPF`."
                        },
                        "customer_id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "The customer this job belongs to."
                        },
                        "vehicle_id": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The vehicle being worked on, when one is attached."
                        },
                        "stage": {
                          "type": "string",
                          "enum": [
                            "lead",
                            "scheduled",
                            "in_progress",
                            "curing",
                            "qa",
                            "ready",
                            "completed",
                            "canceled"
                          ],
                          "description": "Where the job sits on the board."
                        },
                        "assignee_id": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "Assigned staff — a **staff profile** id, which is the `id` from `GET /api/v1/staff`, not that row's `user_id`."
                        },
                        "scheduled_start": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "Booked start, or `null` while the job is unscheduled."
                        },
                        "scheduled_end": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "Booked end, or `null` while the job is unscheduled."
                        },
                        "actual_start": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "When work really began — stamped the first time the job reaches `in_progress` or beyond, and never cleared by a move backwards."
                        },
                        "actual_end": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "When work finished. Re-stamped on every entry into `completed`, and cleared when the job leaves it."
                        },
                        "location_address": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Where the work happens, for mobile jobs."
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "When the job was created."
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": {
                    "id": "4a92c7f1-8d36-4b05-9e2a-1f6b3d8c50e7",
                    "number": 317,
                    "title": "Full-front PPF",
                    "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                    "vehicle_id": "0d5e8b31-7f24-4a96-b3c8-e2517da9c064",
                    "stage": "in_progress",
                    "assignee_id": null,
                    "scheduled_start": "2026-07-16T18:03:11.482Z",
                    "scheduled_end": null,
                    "actual_start": "2026-07-16T18:03:11.482Z",
                    "actual_end": null,
                    "location_address": null,
                    "created_at": "2026-07-16T18:03:11.482Z"
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No job with that id in this shop.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "not_found"
                          ],
                          "description": "No job with that id in this shop."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "update-job-stage",
        "summary": "Move a job to another stage",
        "description": "The one job mutation with no scheduling invariant to violate, and it behaves exactly like a drag on the board: `actual_start` is stamped the first time the job reaches `in_progress` or beyond and never cleared by a move backwards, `actual_end` is re-stamped on every entry into `completed` and cleared when it leaves, and the move goes through the same event rail, so automations, the activity timeline and webhooks all see it. Setting the stage the job already has is a no-op that returns the job, so a retry is safe. If the job moved underneath you, you get a 409 rather than a silent overwrite.",
        "tags": [
          "Jobs"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The job's id.",
            "schema": {
              "type": "string"
            },
            "example": "4a92c7f1-8d36-4b05-9e2a-1f6b3d8c50e7"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "The stage to move to.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "stage": {
                    "type": "string",
                    "enum": [
                      "lead",
                      "scheduled",
                      "in_progress",
                      "curing",
                      "qa",
                      "ready",
                      "completed",
                      "canceled"
                    ],
                    "description": "The board stage."
                  }
                },
                "required": [
                  "stage"
                ]
              },
              "example": {
                "stage": "completed"
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The job at its new stage.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Service VIN's id for the job."
                        },
                        "number": {
                          "type": "integer",
                          "description": "The shop-visible job number."
                        },
                        "title": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "What the job is, e.g. `Full-front PPF`."
                        },
                        "customer_id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "The customer this job belongs to."
                        },
                        "vehicle_id": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The vehicle being worked on, when one is attached."
                        },
                        "stage": {
                          "type": "string",
                          "enum": [
                            "lead",
                            "scheduled",
                            "in_progress",
                            "curing",
                            "qa",
                            "ready",
                            "completed",
                            "canceled"
                          ],
                          "description": "Where the job sits on the board."
                        },
                        "assignee_id": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "Assigned staff — a **staff profile** id, which is the `id` from `GET /api/v1/staff`, not that row's `user_id`."
                        },
                        "scheduled_start": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "Booked start, or `null` while the job is unscheduled."
                        },
                        "scheduled_end": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "Booked end, or `null` while the job is unscheduled."
                        },
                        "actual_start": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "When work really began — stamped the first time the job reaches `in_progress` or beyond, and never cleared by a move backwards."
                        },
                        "actual_end": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "When work finished. Re-stamped on every entry into `completed`, and cleared when the job leaves it."
                        },
                        "location_address": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Where the work happens, for mobile jobs."
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "When the job was created."
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": {
                    "id": "4a92c7f1-8d36-4b05-9e2a-1f6b3d8c50e7",
                    "number": 317,
                    "title": "Full-front PPF",
                    "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                    "vehicle_id": "0d5e8b31-7f24-4a96-b3c8-e2517da9c064",
                    "stage": "completed",
                    "assignee_id": null,
                    "scheduled_start": "2026-07-16T18:03:11.482Z",
                    "scheduled_end": null,
                    "actual_start": "2026-07-16T18:03:11.482Z",
                    "actual_end": "2026-07-16T18:03:11.482Z",
                    "location_address": null,
                    "created_at": "2026-07-16T18:03:11.482Z"
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not. The key is read-only and this endpoint writes. Mint a full-access key; the scope is fixed when a key is created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No job with that id in this shop.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "not_found"
                          ],
                          "description": "No job with that id in this shop."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "409": {
            "description": "The job moved to a different stage while the request was in flight, or the move collided with a bay that is already booked for that time.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "conflict"
                          ],
                          "description": "The job moved to a different stage while the request was in flight, or the move collided with a bay that is already booked for that time."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "422": {
            "description": "`stage` was missing or not a board stage.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "validation_error"
                          ],
                          "description": "`stage` was missing or not a board stage."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/appointments": {
      "get": {
        "operationId": "list-appointments",
        "summary": "List scheduled work in a time window",
        "description": "Jobs that have a `scheduled_start`, in chronological order, with the customer and vehicle inlined so a reminder needs one call rather than three. Windowed rather than paginated: the shared cursor walks `created_at` descending, which is the wrong order for a diary, so narrow `from`/`to` instead of paging. Canceled jobs are excluded unless you ask for that stage explicitly, and so are appointments that arrived through a data import — this is a diary of work happening in the shop's bays, and migrated bookings are reached with `?imported=true`. `meta.truncated` is true when the window hit the row ceiling and hid appointments.",
        "tags": [
          "Appointments"
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "ISO 8601 start of the window. Defaults to now.",
            "schema": {
              "type": "string"
            },
            "example": "2026-08-01T00:00:00Z"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "ISO 8601 end of the window. Defaults to 30 days after `from`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "stage",
            "in": "query",
            "required": false,
            "description": "Only this stage. Supplying it also lifts the canceled-jobs exclusion.",
            "schema": {
              "type": "string",
              "enum": [
                "lead",
                "scheduled",
                "in_progress",
                "curing",
                "qa",
                "ready",
                "completed",
                "canceled"
              ]
            }
          },
          {
            "name": "imported",
            "in": "query",
            "required": false,
            "description": "Return only records that arrived through a data import. Default lists only records created in Service VIN. `1` and `0` are accepted as aliases; any other value is a 422 rather than a silent fallback, because a caller who typos this has been given a wrong answer about which records exist.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "false"
            }
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Appointments in the window, earliest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "The job's id."
                          },
                          "job_number": {
                            "type": "integer",
                            "description": "The shop-visible job number."
                          },
                          "title": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "What the work is."
                          },
                          "stage": {
                            "type": "string",
                            "enum": [
                              "lead",
                              "scheduled",
                              "in_progress",
                              "curing",
                              "qa",
                              "ready",
                              "completed",
                              "canceled"
                            ],
                            "description": "Where the job sits on the board."
                          },
                          "assignee_id": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid",
                            "description": "Assigned staff — a **staff profile** id (`id` from `GET /api/v1/staff`)."
                          },
                          "scheduled_start": {
                            "type": "string",
                            "format": "date-time",
                            "description": "Booked start."
                          },
                          "scheduled_end": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time",
                            "description": "Booked end, when one is set."
                          },
                          "location_address": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Where the work happens, for mobile jobs."
                          },
                          "customer_id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "The customer."
                          },
                          "customer_name": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Inlined so a reminder needs one call."
                          },
                          "customer_email": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "email",
                            "description": "Inlined."
                          },
                          "customer_phone": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Inlined, E.164."
                          },
                          "vehicle_id": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid",
                            "description": "The vehicle, when one is attached."
                          },
                          "vehicle": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "`2024 BMW M3`, inlined."
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time",
                            "description": "When the job was created."
                          }
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "4a92c7f1-8d36-4b05-9e2a-1f6b3d8c50e7",
                      "job_number": 317,
                      "title": "Full-front PPF",
                      "stage": "scheduled",
                      "assignee_id": null,
                      "scheduled_start": "2026-08-04T16:00:00.000Z",
                      "scheduled_end": "2026-08-04T20:00:00.000Z",
                      "location_address": null,
                      "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                      "customer_name": "Jordan Reyes",
                      "customer_email": "jordan@example.com",
                      "customer_phone": "+14035550134",
                      "vehicle_id": "0d5e8b31-7f24-4a96-b3c8-e2517da9c064",
                      "vehicle": "2024 BMW M3",
                      "created_at": "2026-07-16T18:03:11.482Z"
                    }
                  ],
                  "meta": {
                    "from": "2026-08-01T00:00:00.000Z",
                    "to": "2026-08-31T00:00:00.000Z",
                    "truncated": false
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "422": {
            "description": "`from` or `to` was not an ISO 8601 timestamp, or `stage` was not a board stage. `imported` is not `true` or `false` (or their `1`/`0` aliases).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "validation_error"
                          ],
                          "description": "`from` or `to` was not an ISO 8601 timestamp, or `stage` was not a board stage."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "The appointment query failed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "internal_error"
                          ],
                          "description": "The appointment query failed."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/messages": {
      "get": {
        "operationId": "list-messages",
        "summary": "List messages",
        "description": "The shop's message log, newest first — the polling companion to the `message.received` webhook, and the way to read a thread you were told about.",
        "tags": [
          "Messages"
        ],
        "parameters": [
          {
            "name": "customer_id",
            "in": "query",
            "required": false,
            "description": "Only messages matched to this customer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "conversation_id",
            "in": "query",
            "required": false,
            "description": "Only messages in this inbox thread.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "required": false,
            "description": "`inbound` is from the customer.",
            "schema": {
              "type": "string",
              "enum": [
                "inbound",
                "outbound"
              ]
            },
            "example": "inbound"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Rows per page. Values outside 1–100 are clamped; anything unparseable falls back to the default.",
            "schema": {
              "type": "integer",
              "default": 25,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The previous page's `meta.next_cursor`. Opaque — decode nothing, pass it back verbatim.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "A page of messages, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Service VIN's id for the message."
                          },
                          "conversation_id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "The inbox thread this message belongs to."
                          },
                          "customer_id": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid",
                            "description": "The customer, when the thread is matched to one."
                          },
                          "channel": {
                            "type": "string",
                            "description": "`sms`, `email`, `call`, `webchat` or `whatsapp`."
                          },
                          "direction": {
                            "type": "string",
                            "enum": [
                              "inbound",
                              "outbound"
                            ],
                            "description": "`inbound` is from the customer."
                          },
                          "body": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "The message text."
                          },
                          "from": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Sending address or number."
                          },
                          "to": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Receiving address or number."
                          },
                          "status": {
                            "type": "string",
                            "description": "Delivery status as the provider last reported it."
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time",
                            "description": "When the message was recorded."
                          }
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "next_cursor": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Pass back as `?cursor=` for the next page. `null` means this was the last page."
                        }
                      },
                      "required": [
                        "next_cursor"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "5d1e9a73-2f48-4c60-b915-8e3a7c2d4f06",
                      "conversation_id": "a2c79d31-6b40-4e28-9f57-3d8b1a6c2e05",
                      "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                      "channel": "sms",
                      "direction": "inbound",
                      "body": "Is the car ready for pickup today?",
                      "from": "+14035550134",
                      "to": "+14035557890",
                      "status": "delivered",
                      "created_at": "2026-07-16T18:03:11.482Z"
                    }
                  ],
                  "meta": {
                    "next_cursor": null
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "422": {
            "description": "`direction` was not inbound or outbound.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "validation_error"
                          ],
                          "description": "`direction` was not inbound or outbound."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "send-message",
        "summary": "Text a customer",
        "description": "Sends one SMS to a customer of this shop, through the same compliant core the dashboard uses: the shop's messaging switch and Twilio config, a sending number re-proved against the shop's own lines, the opt-out re-check at the send moment, quiet hours, and the inbox thread so the reply lands somewhere. The recipient is always a customer already on file — there is deliberately no raw `to` parameter, because that would make this endpoint a spam cannon borrowing the shop's A2P registration. Every refusal is a 409 naming the reason, since 'opted out', 'quiet hours' and 'messaging not configured' have different fixes.",
        "tags": [
          "Messages"
        ],
        "requestBody": {
          "required": true,
          "description": "Who to text, and what to say.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "customer_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Must be a customer of this shop, with a phone on file."
                  },
                  "body": {
                    "type": "string",
                    "maxLength": 1600,
                    "description": "The message. 1600 is the carrier ceiling for a concatenated SMS, so longer is refused here rather than by the provider."
                  },
                  "channel": {
                    "type": "string",
                    "enum": [
                      "sms"
                    ],
                    "description": "Default: `sms`. Only `sms` today."
                  }
                },
                "required": [
                  "customer_id",
                  "body"
                ]
              },
              "example": {
                "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                "body": "Your car is ready for pickup."
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "The sent message. `id` is null in the rare case where the text went out but the log insert failed — reported truthfully rather than as an error, because a retry would double-text the customer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Service VIN's id for the message."
                        },
                        "conversation_id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "The inbox thread this message belongs to."
                        },
                        "customer_id": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The customer, when the thread is matched to one."
                        },
                        "channel": {
                          "type": "string",
                          "description": "`sms`, `email`, `call`, `webchat` or `whatsapp`."
                        },
                        "direction": {
                          "type": "string",
                          "enum": [
                            "inbound",
                            "outbound"
                          ],
                          "description": "`inbound` is from the customer."
                        },
                        "body": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "The message text."
                        },
                        "from": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Sending address or number."
                        },
                        "to": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Receiving address or number."
                        },
                        "status": {
                          "type": "string",
                          "description": "Delivery status as the provider last reported it."
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "When the message was recorded."
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": {
                    "id": "5d1e9a73-2f48-4c60-b915-8e3a7c2d4f06",
                    "conversation_id": "a2c79d31-6b40-4e28-9f57-3d8b1a6c2e05",
                    "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                    "channel": "sms",
                    "direction": "outbound",
                    "body": "Your car is ready for pickup.",
                    "from": "+14035557890",
                    "to": "+14035550134",
                    "status": "sent",
                    "created_at": "2026-07-16T18:03:11.482Z"
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not. The key is read-only and this endpoint writes. Mint a full-access key; the scope is fixed when a key is created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No customer with that id in this shop.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "not_found"
                          ],
                          "description": "No customer with that id in this shop."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "409": {
            "description": "The customer opted out, it is outside the shop's texting hours, or the shop has no working sender. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "conflict"
                          ],
                          "description": "The customer opted out, it is outside the shop's texting hours, or the shop has no working sender. The message says which."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "422": {
            "description": "The body was empty or too long, or that customer has no phone number on file.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "validation_error"
                          ],
                          "description": "The body was empty or too long, or that customer has no phone number on file."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/services": {
      "get": {
        "operationId": "list-services",
        "summary": "List the service menu",
        "description": "The shop's services, alphabetical, with the category name inlined. Active services only unless you pass `active=false`. Not paginated — a menu is a menu.",
        "tags": [
          "Services & staff"
        ],
        "parameters": [
          {
            "name": "active",
            "in": "query",
            "required": false,
            "description": "`false` lists the retired services instead.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "true"
            }
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The service menu.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Service VIN's id for the service."
                          },
                          "name": {
                            "type": "string",
                            "description": "Menu name."
                          },
                          "description": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Longer description."
                          },
                          "sku": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "The shop's own code."
                          },
                          "category": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Category name, inlined."
                          },
                          "base_price": {
                            "type": [
                              "number",
                              "null"
                            ],
                            "description": "List price in the shop's currency."
                          },
                          "pricing_model": {
                            "type": "string",
                            "description": "How the price is worked out."
                          },
                          "default_duration_minutes": {
                            "type": [
                              "integer",
                              "null"
                            ],
                            "description": "Default booking length."
                          },
                          "is_active": {
                            "type": "boolean",
                            "description": "Whether the shop still sells it."
                          }
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "8f2b6d14-3a95-4e07-b2c6-71d5e9a3f480",
                      "name": "Full-front PPF",
                      "description": "Hood, fenders, mirrors and bumper.",
                      "sku": "PPF-FF",
                      "category": "Paint protection film",
                      "base_price": 2200,
                      "pricing_model": "flat",
                      "default_duration_minutes": 480,
                      "is_active": true
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "The service query failed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "internal_error"
                          ],
                          "description": "The service query failed."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/staff": {
      "get": {
        "operationId": "list-staff",
        "summary": "List staff",
        "description": "The shop's roster, alphabetical, for assignment dropdowns. Not paginated. **The two ids are not interchangeable**: `id` is a staff-profile id and assigns a JOB, `user_id` is a login id and assigns a LEAD. `user_id` is null for a staff profile with no login, which is why they cannot be collapsed into one field.",
        "tags": [
          "Services & staff"
        ],
        "parameters": [
          {
            "name": "bookable",
            "in": "query",
            "required": false,
            "description": "Narrow to staff who can (or cannot) be scheduled.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The roster.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Staff-profile id. This is what `jobs.assignee_id` points at — use it to assign a JOB."
                          },
                          "user_id": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid",
                            "description": "The person's login id, and what `leads.assigned_to` points at — use it to assign a LEAD. Null for a staff profile with no login, which is why the two ids cannot be used interchangeably."
                          },
                          "name": {
                            "type": "string",
                            "description": "Display name, falling back to the login's name and then its email."
                          },
                          "is_bookable": {
                            "type": "boolean",
                            "description": "Whether they can be scheduled."
                          },
                          "skills": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            },
                            "description": "Skill tags. Empty array when none are set."
                          }
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "c73e5a91-8d24-4f6b-90e7-2a5c8f1b3d46",
                      "user_id": "e15c3b78-4a92-4d05-8f61-7b2e9c4a6d38",
                      "name": "Alex Mercer",
                      "is_bookable": true,
                      "skills": [
                        "ppf",
                        "tint"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "The staff query failed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "internal_error"
                          ],
                          "description": "The staff query failed."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/hooks": {
      "get": {
        "operationId": "list-hooks",
        "summary": "List webhook subscriptions",
        "description": "Every webhook endpoint on the shop, newest first. Signing secrets are never returned here — they are shown once, at subscribe time. This list is not paginated: the ceiling is 10 endpoints per shop, so there is no `meta` block.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Every endpoint on the shop.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Pass this to `DELETE /api/v1/hooks/{id}` to unsubscribe."
                          },
                          "url": {
                            "type": "string",
                            "format": "uri",
                            "description": "Where deliveries are POSTed."
                          },
                          "description": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Label shown in the dashboard."
                          },
                          "events": {
                            "type": "array",
                            "items": {
                              "type": "string",
                              "enum": [
                                "lead.created",
                                "lead.status_changed",
                                "lead.assigned",
                                "quote.sent",
                                "quote.accepted",
                                "quote.declined",
                                "job.created",
                                "job.stage_changed",
                                "job.completed",
                                "job.assigned",
                                "appointment.booked",
                                "appointment.rescheduled",
                                "appointment.canceled",
                                "invoice.paid",
                                "message.received",
                                "message.sent",
                                "message.delivery_failed",
                                "conversation.assigned",
                                "call.missed",
                                "call.completed",
                                "call.recording_ready",
                                "call.transcript_ready",
                                "warranty.issued",
                                "training.requested",
                                "training.enrolled",
                                "training.deposit_paid",
                                "training.completed",
                                "training.certified",
                                "review.private_feedback"
                              ]
                            },
                            "description": "Subscribed events. An empty array means every event."
                          },
                          "active": {
                            "type": "boolean",
                            "description": "Endpoints auto-pause after 10 consecutive delivery failures and are resumed from the dashboard."
                          },
                          "consecutive_failures": {
                            "type": "integer",
                            "description": "Failed deliveries in a row. A single success resets it to 0."
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time",
                            "description": "When the subscription was made."
                          }
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "3e7a1c4e-5b92-4f08-a6d3-8c204f7b1e59",
                      "url": "https://hooks.zapier.com/hooks/catch/123456/abcdef/",
                      "description": "Zapier/Make subscription",
                      "events": [
                        "lead.created"
                      ],
                      "active": true,
                      "consecutive_failures": 0,
                      "created_at": "2026-07-16T18:03:11.482Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "The endpoint query failed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "internal_error"
                          ],
                          "description": "The endpoint query failed."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "create-hook",
        "summary": "Subscribe to events",
        "description": "Registers an https URL to receive signed event deliveries. The response carries the signing secret **once** — store it, because it is never shown again. The URL is checked against private, loopback and link-local ranges before it is saved, and again on every delivery.",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "description": "The endpoint to subscribe.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "maxLength": 2000,
                    "description": "Must be `https://` and must resolve to a public host."
                  },
                  "events": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "lead.created",
                        "lead.status_changed",
                        "lead.assigned",
                        "quote.sent",
                        "quote.accepted",
                        "quote.declined",
                        "job.created",
                        "job.stage_changed",
                        "job.completed",
                        "job.assigned",
                        "appointment.booked",
                        "appointment.rescheduled",
                        "appointment.canceled",
                        "invoice.paid",
                        "message.received",
                        "message.sent",
                        "message.delivery_failed",
                        "conversation.assigned",
                        "call.missed",
                        "call.completed",
                        "call.recording_ready",
                        "call.transcript_ready",
                        "warranty.issued",
                        "training.requested",
                        "training.enrolled",
                        "training.deposit_paid",
                        "training.completed",
                        "training.certified",
                        "review.private_feedback"
                      ]
                    },
                    "description": "Default: `[] (every event)`. Which events to receive. Omit it, or send `[]`, to subscribe to everything."
                  }
                },
                "required": [
                  "url"
                ]
              },
              "example": {
                "url": "https://hooks.zapier.com/hooks/catch/123456/abcdef/",
                "events": [
                  "lead.created"
                ]
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "The subscription, plus the signing secret — the only time it is returned.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Pass this to `DELETE /api/v1/hooks/{id}`."
                        },
                        "url": {
                          "type": "string",
                          "format": "uri",
                          "description": "Where deliveries will be POSTed."
                        },
                        "events": {
                          "type": "array",
                          "items": {
                            "type": "string",
                            "enum": [
                              "lead.created",
                              "lead.status_changed",
                              "lead.assigned",
                              "quote.sent",
                              "quote.accepted",
                              "quote.declined",
                              "job.created",
                              "job.stage_changed",
                              "job.completed",
                              "job.assigned",
                              "appointment.booked",
                              "appointment.rescheduled",
                              "appointment.canceled",
                              "invoice.paid",
                              "message.received",
                              "message.sent",
                              "message.delivery_failed",
                              "conversation.assigned",
                              "call.missed",
                              "call.completed",
                              "call.recording_ready",
                              "call.transcript_ready",
                              "warranty.issued",
                              "training.requested",
                              "training.enrolled",
                              "training.deposit_paid",
                              "training.completed",
                              "training.certified",
                              "review.private_feedback"
                            ]
                          },
                          "description": "What you subscribed to."
                        },
                        "secret": {
                          "type": "string",
                          "description": "The `whsec_…` signing secret. Shown once. Store it now — it verifies every delivery."
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": {
                    "id": "3e7a1c4e-5b92-4f08-a6d3-8c204f7b1e59",
                    "url": "https://hooks.zapier.com/hooks/catch/123456/abcdef/",
                    "events": [
                      "lead.created"
                    ],
                    "secret": "whsec_EXAMPLE_ONLY_yours_will_differ"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The body was not valid JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "invalid_request"
                          ],
                          "description": "The body was not valid JSON."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Webhooks are a Growth-plan feature and this shop is on a lower plan. The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not. The key is read-only and this endpoint writes. Mint a full-access key; the scope is fixed when a key is created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_required"
                          ],
                          "description": "Webhooks are a Growth-plan feature and this shop is on a lower plan."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "409": {
            "description": "The shop already has 10 endpoints. Delete one first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "conflict"
                          ],
                          "description": "The shop already has 10 endpoints. Delete one first."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "422": {
            "description": "`url` is not https, is not a valid URL, names an unknown event, or resolves to a private/loopback host.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "validation_error"
                          ],
                          "description": "`url` is not https, is not a valid URL, names an unknown event, or resolves to a private/loopback host."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "The subscription could not be stored.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "internal_error"
                          ],
                          "description": "The subscription could not be stored."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/hooks/{id}": {
      "delete": {
        "operationId": "delete-hook",
        "summary": "Unsubscribe",
        "description": "Removes the subscription and its signing secret. Scoped to your shop: an id belonging to another shop reads as `not_found`, never as forbidden-but-real.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The subscription id from the subscribe response or the list.",
            "schema": {
              "type": "string"
            },
            "example": "3e7a1c4e-5b92-4f08-a6d3-8c204f7b1e59"
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "204": {
            "description": "Removed. No body."
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not. The key is read-only and this endpoint writes. Mint a full-access key; the scope is fixed when a key is created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No such subscription on this shop.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "not_found"
                          ],
                          "description": "No such subscription on this shop."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "The delete failed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "internal_error"
                          ],
                          "description": "The delete failed."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/openapi.json": {
      "get": {
        "operationId": "get-openapi",
        "summary": "The OpenAPI 3.1 document",
        "description": "This whole reference as a machine-readable spec — import it into Postman, Insomnia, or any OpenAPI client generator. No authentication required, because a spec is not data.",
        "tags": [
          "OpenAPI spec"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "An OpenAPI 3.1 document describing every endpoint above.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object"
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "openapi": "3.1.0",
                  "info": {
                    "title": "Service VIN API",
                    "version": "1.0.0"
                  },
                  "servers": [
                    {
                      "url": "https://www.servicevin.com"
                    }
                  ],
                  "paths": {
                    "/api/v1/me": {
                      "get": {
                        "operationId": "get-me"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/calls": {
      "get": {
        "operationId": "list-calls",
        "summary": "List calls",
        "description": "The shop's phone log, newest first. Service VIN records, transcribes and summarizes every call; this is the record of what happened, not the audio and not the words. `has_recording`, `has_voicemail`, `has_transcript` and `has_ai_summary` say which artefacts exist, and each is fetched from its own endpoint — so a key that reads the log does not thereby hold every customer's recorded voice.\n\nPages by `offset` rather than by the cursor the older resources use. `meta.total` is the exact number of calls matching the filter and `meta.omitted` how many are not in this page: answer \"how many did we miss\" from `total`, never from the length of `data`.",
        "tags": [
          "Calls"
        ],
        "parameters": [
          {
            "name": "direction",
            "in": "query",
            "required": false,
            "description": "`inbound` is the customer ringing the shop.",
            "schema": {
              "type": "string",
              "enum": [
                "inbound",
                "outbound"
              ]
            },
            "example": "inbound"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "How the call ended. `missed` is what a call-back list wants.",
            "schema": {
              "type": "string",
              "enum": [
                "ringing",
                "in_progress",
                "completed",
                "missed",
                "failed",
                "canceled"
              ]
            }
          },
          {
            "name": "customer_id",
            "in": "query",
            "required": false,
            "description": "Only this customer's calls.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "ISO instant. Only calls that started at or after it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "description": "ISO instant. Only calls that started before it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many to return, 1-100.",
            "schema": {
              "type": "integer",
              "default": 25,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "How many to skip. Pass `meta.next_offset` from the previous response to continue.",
            "schema": {
              "type": "integer",
              "default": "0"
            }
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "A page of calls, newest first. `meta.total` is the exact match count, `meta.omitted` how many this page left out, and `meta.next_offset` the offset to ask for next (null when there is no more).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Service VIN's id for the call."
                          },
                          "conversation": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid",
                            "description": "The inbox thread this call was filed into. Null when the number was never matched to a contact."
                          },
                          "customer_id": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid",
                            "description": "The customer, when the caller is on file."
                          },
                          "direction": {
                            "type": "string",
                            "enum": [
                              "inbound",
                              "outbound"
                            ],
                            "description": "`inbound` is the customer ringing the shop."
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "ringing",
                              "in_progress",
                              "completed",
                              "missed",
                              "failed",
                              "canceled"
                            ],
                            "description": "How it ended. `ringing` and `in_progress` are calls happening right now, so a report about yesterday should exclude them."
                          },
                          "from": {
                            "type": "string",
                            "description": "The calling number, E.164."
                          },
                          "to": {
                            "type": "string",
                            "description": "The number called, E.164."
                          },
                          "started_at": {
                            "type": "string",
                            "format": "date-time",
                            "description": "When it started."
                          },
                          "ended_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time",
                            "description": "When it ended. Null while the call is still up."
                          },
                          "duration_seconds": {
                            "type": [
                              "integer",
                              "null"
                            ],
                            "description": "The whole call, ringing included."
                          },
                          "answered_by": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Who or what picked it up — a member of staff, or the AI receptionist."
                          },
                          "has_recording": {
                            "type": "boolean",
                            "description": "Audio of the conversation exists. Fetch a signed link from GET /api/v1/calls/{id}/recording."
                          },
                          "recording_duration_seconds": {
                            "type": [
                              "integer",
                              "null"
                            ],
                            "description": "The recorded part only, which starts when somebody answers — shorter than `duration_seconds` on a call that rang first."
                          },
                          "has_voicemail": {
                            "type": "boolean",
                            "description": "The caller left a message. Fetch it from the same endpoint with `?media=voicemail`."
                          },
                          "voicemail_duration_seconds": {
                            "type": [
                              "integer",
                              "null"
                            ],
                            "description": "How long the voicemail runs."
                          },
                          "has_transcript": {
                            "type": "boolean",
                            "description": "The words are available from GET /api/v1/calls/{id}/transcript."
                          },
                          "has_ai_summary": {
                            "type": "boolean",
                            "description": "Service VIN has analysed this call and produced a recap."
                          }
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "8c14f0b7-3d95-42ae-9b6c-0e7a5d3f21b8",
                      "conversation": "a2c79d31-6b40-4e28-9f57-3d8b1a6c2e05",
                      "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                      "direction": "inbound",
                      "status": "missed",
                      "from": "+14035550134",
                      "to": "+14035557890",
                      "started_at": "2026-07-16T18:03:11.482Z",
                      "ended_at": "2026-07-16T18:03:11.482Z",
                      "duration_seconds": 24,
                      "answered_by": null,
                      "has_recording": false,
                      "recording_duration_seconds": null,
                      "has_voicemail": true,
                      "voicemail_duration_seconds": 17,
                      "has_transcript": true,
                      "has_ai_summary": false
                    }
                  ],
                  "meta": {
                    "total": 41,
                    "omitted": 40,
                    "next_offset": 1
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "422": {
            "description": "`direction` or `status` was not one of the listed values.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "validation_error"
                          ],
                          "description": "`direction` or `status` was not one of the listed values."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/calls/{id}": {
      "get": {
        "operationId": "get-call",
        "summary": "Get a call",
        "description": "One call's record. There is no PUT, PATCH or DELETE on this path and there will not be: a recorded call is history, and the same is true of every message on this API.\n\n`duration_seconds` is the whole call; `recording_duration_seconds` is only the part after somebody answered. They differ on a call that rang first, and reporting one as the other overstates talk time.",
        "tags": [
          "Calls"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The call's id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Service VIN's id for the call."
                        },
                        "conversation": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The inbox thread this call was filed into. Null when the number was never matched to a contact."
                        },
                        "customer_id": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The customer, when the caller is on file."
                        },
                        "direction": {
                          "type": "string",
                          "enum": [
                            "inbound",
                            "outbound"
                          ],
                          "description": "`inbound` is the customer ringing the shop."
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "ringing",
                            "in_progress",
                            "completed",
                            "missed",
                            "failed",
                            "canceled"
                          ],
                          "description": "How it ended. `ringing` and `in_progress` are calls happening right now, so a report about yesterday should exclude them."
                        },
                        "from": {
                          "type": "string",
                          "description": "The calling number, E.164."
                        },
                        "to": {
                          "type": "string",
                          "description": "The number called, E.164."
                        },
                        "started_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "When it started."
                        },
                        "ended_at": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "When it ended. Null while the call is still up."
                        },
                        "duration_seconds": {
                          "type": [
                            "integer",
                            "null"
                          ],
                          "description": "The whole call, ringing included."
                        },
                        "answered_by": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Who or what picked it up — a member of staff, or the AI receptionist."
                        },
                        "has_recording": {
                          "type": "boolean",
                          "description": "Audio of the conversation exists. Fetch a signed link from GET /api/v1/calls/{id}/recording."
                        },
                        "recording_duration_seconds": {
                          "type": [
                            "integer",
                            "null"
                          ],
                          "description": "The recorded part only, which starts when somebody answers — shorter than `duration_seconds` on a call that rang first."
                        },
                        "has_voicemail": {
                          "type": "boolean",
                          "description": "The caller left a message. Fetch it from the same endpoint with `?media=voicemail`."
                        },
                        "voicemail_duration_seconds": {
                          "type": [
                            "integer",
                            "null"
                          ],
                          "description": "How long the voicemail runs."
                        },
                        "has_transcript": {
                          "type": "boolean",
                          "description": "The words are available from GET /api/v1/calls/{id}/transcript."
                        },
                        "has_ai_summary": {
                          "type": "boolean",
                          "description": "Service VIN has analysed this call and produced a recap."
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": {
                    "id": "8c14f0b7-3d95-42ae-9b6c-0e7a5d3f21b8",
                    "conversation": "a2c79d31-6b40-4e28-9f57-3d8b1a6c2e05",
                    "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                    "direction": "inbound",
                    "status": "completed",
                    "from": "+14035550134",
                    "to": "+14035557890",
                    "started_at": "2026-07-16T18:03:11.482Z",
                    "ended_at": "2026-07-16T18:03:11.482Z",
                    "duration_seconds": 214,
                    "answered_by": "Front desk",
                    "has_recording": true,
                    "recording_duration_seconds": 196,
                    "has_voicemail": false,
                    "voicemail_duration_seconds": null,
                    "has_transcript": true,
                    "has_ai_summary": true
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No call with that id in this shop.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "not_found"
                          ],
                          "description": "No call with that id in this shop."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/calls/{id}/recording": {
      "get": {
        "operationId": "get-call-recording",
        "summary": "Get a signed link to a call recording",
        "description": "Returns a SHORT-LIVED SIGNED URL for one call's audio, and the instant it stops working. It does not return the audio, and it never returns the provider's own URL — that link is copyable, outlives the API key that revealed it, and on one of our two upstreams is fetched with the platform's own account credential.\n\nTHE RETURNED LINK IS BEARER-EQUIVALENT until it expires: anyone holding it can play that one call's audio with no further authentication. That is what makes it usable by a media player, and it is why the window is minutes. Do not store it — fetch a fresh one.\n\nIt names ONE call and ONE media kind and cannot be widened. `?ttl=` is clamped to 900 seconds however large a number you send, so read `expires_at` rather than assuming what you asked for.\n\nCalls on this platform are recorded under a disclosure regime the shop configures; that decision was made when the call was answered and fetching the audio does not change it.",
        "tags": [
          "Calls"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The call's id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "media",
            "in": "query",
            "required": false,
            "description": "The recorded conversation, or the message the caller left.",
            "schema": {
              "type": "string",
              "enum": [
                "recording",
                "voicemail"
              ],
              "default": "recording"
            }
          },
          {
            "name": "ttl",
            "in": "query",
            "required": false,
            "description": "Seconds the link should live, 30-900. Larger values are clamped to 900.",
            "schema": {
              "type": "integer",
              "default": "300"
            }
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "A signed URL and the instant it expires.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "call": {
                          "type": "string",
                          "format": "uuid",
                          "description": "The call the link is for."
                        },
                        "kind": {
                          "type": "string",
                          "enum": [
                            "recording",
                            "voicemail"
                          ],
                          "description": "Which audio the link fetches."
                        },
                        "url": {
                          "type": "string",
                          "format": "uri",
                          "description": "The signed link. Points at Service VIN, never at the storage provider."
                        },
                        "expires_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "When the link stops working. The authoritative value — read it."
                        },
                        "duration_seconds": {
                          "type": [
                            "integer",
                            "null"
                          ],
                          "description": "How long the audio runs."
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": {
                    "call": "8c14f0b7-3d95-42ae-9b6c-0e7a5d3f21b8",
                    "kind": "recording",
                    "url": "https://www.servicevin.com/api/calls/media/8c14f0b7-3d95-42ae-9b6c-0e7a5d3f21b8?token=eyJz…",
                    "expires_at": "2026-07-16T18:03:11.482Z",
                    "duration_seconds": 196
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No call with that id in this shop.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "not_found"
                          ],
                          "description": "No call with that id in this shop."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "That call has no audio of the requested kind, or this deployment has no public site URL configured.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "internal_error"
                          ],
                          "description": "That call has no audio of the requested kind, or this deployment has no public site URL configured."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/calls/{id}/transcript": {
      "get": {
        "operationId": "get-call-transcript",
        "summary": "Read a call transcript",
        "description": "What was said on one call, as text. Separate from the call record on purpose: a call's LOG entry and its customer's WORDS are different sensitivities, and folding them together would mean every list-and-fetch integration held the words whether it needed them or not.\n\nNot every call has one — a short wrong number has audio and no transcript — and `has_transcript` on the call record says which before you ask. `source` names what produced it: a live-agent capture, or an after-the-fact machine transcription that carries the usual mishearings of names, plates and prices. Treat a figure read out of a transcript as something to confirm, never as the price.",
        "tags": [
          "Calls"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The call's id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The transcript, or nulls when the call has none.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "call": {
                          "type": "string",
                          "format": "uuid",
                          "description": "The call."
                        },
                        "transcript": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "What was said. Null when the call was never transcribed."
                        },
                        "source": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "What produced it — a live capture, or a transcription of the recording."
                        },
                        "started_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "When the call started."
                        },
                        "duration_seconds": {
                          "type": [
                            "integer",
                            "null"
                          ],
                          "description": "How long the call ran."
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": {
                    "call": "8c14f0b7-3d95-42ae-9b6c-0e7a5d3f21b8",
                    "transcript": "Caller: Hi, is the black Model 3 ready?\\nShop: It is — we finished the front bumper this morning.",
                    "source": "live_agent",
                    "started_at": "2026-07-16T18:03:11.482Z",
                    "duration_seconds": 214
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No call with that id in this shop.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "not_found"
                          ],
                          "description": "No call with that id in this shop."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/conversations": {
      "get": {
        "operationId": "list-conversations",
        "summary": "List conversations",
        "description": "The shop's inbox, most recently active first. `?unread=true` is the one to reach for: unread here means the customer's last message landed after our last outbound — the ball is in the shop's court — which is what \"what needs answering\" actually means. It is derived from two timestamps rather than being a flag somebody set.\n\n`status` is the shop's disposition rather than the customer's: `open` is live, `closed` is dealt with (Quo calls this done), `snoozed` is parked. A snoozed thread reopens on the next inbound.",
        "tags": [
          "Conversations"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only threads at this disposition.",
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "snoozed",
                "closed"
              ]
            },
            "example": "open"
          },
          {
            "name": "channel",
            "in": "query",
            "required": false,
            "description": "Only threads on this channel.",
            "schema": {
              "type": "string",
              "enum": [
                "sms",
                "email",
                "call",
                "webchat",
                "whatsapp"
              ]
            }
          },
          {
            "name": "customer_id",
            "in": "query",
            "required": false,
            "description": "Only this customer's threads.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "assigned_to",
            "in": "query",
            "required": false,
            "description": "Only threads owned by this teammate.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "unassigned",
            "in": "query",
            "required": false,
            "description": "`true` for threads nobody has taken. Ignored when `assigned_to` is given.",
            "schema": {
              "type": "string",
              "enum": [
                "true"
              ]
            }
          },
          {
            "name": "unread",
            "in": "query",
            "required": false,
            "description": "`true` for threads whose last word was the customer's.",
            "schema": {
              "type": "string",
              "enum": [
                "true"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many to return, 1-100.",
            "schema": {
              "type": "integer",
              "default": 25,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "How many to skip. Pass `meta.next_offset` from the previous response to continue.",
            "schema": {
              "type": "integer",
              "default": "0"
            }
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "A page of threads, most recently active first, with `meta.total`, `meta.omitted` and `meta.next_offset`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Service VIN's id for the thread."
                          },
                          "customer_id": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid",
                            "description": "The customer, when the thread is matched to one."
                          },
                          "channel": {
                            "type": "string",
                            "enum": [
                              "sms",
                              "email",
                              "call",
                              "webchat",
                              "whatsapp"
                            ],
                            "description": "What the thread runs on."
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "open",
                              "snoozed",
                              "closed"
                            ],
                            "description": "The shop's disposition. `closed` is what Quo calls done; a new inbound reopens a thread either way."
                          },
                          "subject": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Subject line, on an email thread."
                          },
                          "contact_number": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "The number on the other end, when the thread is a text thread."
                          },
                          "assigned_to": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid",
                            "description": "The teammate who owns it, or null when nobody has taken it."
                          },
                          "pinned": {
                            "type": "boolean",
                            "description": "Pinned to the top of the shop's inbox."
                          },
                          "unread": {
                            "type": "boolean",
                            "description": "The customer's last message landed after our last outbound — i.e. the ball is in the shop's court. Derived from the two timestamps, not a flag somebody set."
                          },
                          "is_ai_managed": {
                            "type": "boolean",
                            "description": "Service VIN's own agent is answering this thread."
                          },
                          "last_message_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time",
                            "description": "When anything last happened on it."
                          },
                          "last_inbound_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time",
                            "description": "When the customer last wrote."
                          },
                          "last_outbound_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time",
                            "description": "When the shop last wrote — including anything sent automatically."
                          },
                          "last_human_outbound_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time",
                            "description": "When a PERSON at the shop last replied. Automated sends — an after-hours acknowledgement, a missed-call text-back, an automation rule — move `last_outbound_at` and never this, so `last_inbound_at > last_human_outbound_at` is the shop's own \"still waiting on us\" lens. Null when nobody has ever replied by hand."
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time",
                            "description": "When it opened."
                          }
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "a2c79d31-6b40-4e28-9f57-3d8b1a6c2e05",
                      "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                      "channel": "sms",
                      "status": "open",
                      "subject": null,
                      "contact_number": "+14035550134",
                      "assigned_to": null,
                      "pinned": false,
                      "unread": true,
                      "is_ai_managed": false,
                      "last_message_at": "2026-07-16T18:03:11.482Z",
                      "last_inbound_at": "2026-07-16T18:03:11.482Z",
                      "last_outbound_at": null,
                      "last_human_outbound_at": null,
                      "created_at": "2026-07-16T18:03:11.482Z"
                    }
                  ],
                  "meta": {
                    "total": 12,
                    "omitted": 11,
                    "next_offset": 1
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "422": {
            "description": "`status` or `channel` was not one of the listed values.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "validation_error"
                          ],
                          "description": "`status` or `channel` was not one of the listed values."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/conversations/{id}": {
      "get": {
        "operationId": "get-conversation",
        "summary": "Get a conversation",
        "description": "One thread, plus the two things a reply depends on: who the contact is, and whether the shop is allowed to text them.\n\nRead `texting_blocked` BEFORE composing anything. True means a STOP or a staff block is on file, and the send endpoint will refuse — correctly. `marketing_consent` is a different question with a different answer: it governs campaigns, not replies, and a customer who consented to nothing may still be answered when they wrote in first.\n\nThe messages themselves come from `GET /api/v1/messages?conversation_id=…`.",
        "tags": [
          "Conversations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The thread's id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The thread and its contact's messaging standing.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "conversation": {
                          "type": "object",
                          "description": "The thread record — the same fields the list returns."
                        },
                        "customer_id": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The contact behind the thread."
                        },
                        "customer_name": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Their display name."
                        },
                        "customer_phone": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Their number."
                        },
                        "customer_email": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Their address."
                        },
                        "texting_blocked": {
                          "type": "boolean",
                          "description": "A STOP or a staff block is on file. Sending will be refused; do not draft a text, and do not retry the refusal."
                        },
                        "marketing_consent": {
                          "type": "boolean",
                          "description": "Whether campaigns may reach them. Not the same question as replying."
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": {
                    "conversation": {
                      "id": "a2c79d31-6b40-4e28-9f57-3d8b1a6c2e05",
                      "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                      "channel": "sms",
                      "status": "open",
                      "subject": null,
                      "contact_number": "+14035550134",
                      "assigned_to": null,
                      "pinned": false,
                      "unread": true,
                      "is_ai_managed": false,
                      "last_message_at": "2026-07-16T18:03:11.482Z",
                      "last_inbound_at": "2026-07-16T18:03:11.482Z",
                      "last_outbound_at": null,
                      "last_human_outbound_at": null,
                      "created_at": "2026-07-16T18:03:11.482Z"
                    },
                    "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                    "customer_name": "Ben Carter",
                    "customer_phone": "+14035550134",
                    "customer_email": "ben@example.com",
                    "texting_blocked": false,
                    "marketing_consent": true
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No thread with that id in this shop.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "not_found"
                          ],
                          "description": "No thread with that id in this shop."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "update-conversation",
        "summary": "Change one thing about a conversation",
        "description": "A VERB CALL, NOT A PATCH, and deliberately so. Send exactly ONE of `mark_read`, `mark_unread`, `mark_done`, `mark_open`, `snooze`, `pin`, `unpin`, `staff_id` (hand it to that teammate) or `unassign`. Sending none is refused, and so is sending two — one call that both closed a thread and reassigned it would be a single audit row covering two decisions nobody could separate afterwards.\n\nThe MESSAGES are not touchable from here or anywhere: a delivered text is history, and no endpoint on this API edits or deletes one.\n\nAssigning PINGS somebody, so assign when a person is meant to act. The target must be a teammate whose role grants inbox access — anyone else is refused rather than silently parked, because a thread assigned to someone who cannot open the inbox is work that never happens.",
        "tags": [
          "Conversations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The thread's id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Exactly one verb.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mark_read": {
                    "type": "boolean",
                    "description": "Mark the thread read."
                  },
                  "mark_unread": {
                    "type": "boolean",
                    "description": "Put it back to unread."
                  },
                  "mark_done": {
                    "type": "boolean",
                    "description": "Close it (Quo calls this done)."
                  },
                  "mark_open": {
                    "type": "boolean",
                    "description": "Reopen a closed or snoozed thread."
                  },
                  "snooze": {
                    "type": "boolean",
                    "description": "Park it until the next inbound."
                  },
                  "pin": {
                    "type": "boolean",
                    "description": "Pin it to the top of the inbox."
                  },
                  "unpin": {
                    "type": "boolean",
                    "description": "Unpin it."
                  },
                  "staff_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Hand it to this teammate. They are notified."
                  },
                  "unassign": {
                    "type": "boolean",
                    "description": "Take it off whoever holds it."
                  }
                }
              },
              "example": {
                "mark_done": true
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The thread as it now stands.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Service VIN's id for the thread."
                        },
                        "customer_id": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The customer, when the thread is matched to one."
                        },
                        "channel": {
                          "type": "string",
                          "enum": [
                            "sms",
                            "email",
                            "call",
                            "webchat",
                            "whatsapp"
                          ],
                          "description": "What the thread runs on."
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "open",
                            "snoozed",
                            "closed"
                          ],
                          "description": "The shop's disposition. `closed` is what Quo calls done; a new inbound reopens a thread either way."
                        },
                        "subject": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Subject line, on an email thread."
                        },
                        "contact_number": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "The number on the other end, when the thread is a text thread."
                        },
                        "assigned_to": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The teammate who owns it, or null when nobody has taken it."
                        },
                        "pinned": {
                          "type": "boolean",
                          "description": "Pinned to the top of the shop's inbox."
                        },
                        "unread": {
                          "type": "boolean",
                          "description": "The customer's last message landed after our last outbound — i.e. the ball is in the shop's court. Derived from the two timestamps, not a flag somebody set."
                        },
                        "is_ai_managed": {
                          "type": "boolean",
                          "description": "Service VIN's own agent is answering this thread."
                        },
                        "last_message_at": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "When anything last happened on it."
                        },
                        "last_inbound_at": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "When the customer last wrote."
                        },
                        "last_outbound_at": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "When the shop last wrote — including anything sent automatically."
                        },
                        "last_human_outbound_at": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "When a PERSON at the shop last replied. Automated sends — an after-hours acknowledgement, a missed-call text-back, an automation rule — move `last_outbound_at` and never this, so `last_inbound_at > last_human_outbound_at` is the shop's own \"still waiting on us\" lens. Null when nobody has ever replied by hand."
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "When it opened."
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": {
                    "id": "a2c79d31-6b40-4e28-9f57-3d8b1a6c2e05",
                    "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                    "channel": "sms",
                    "status": "closed",
                    "subject": null,
                    "contact_number": "+14035550134",
                    "assigned_to": null,
                    "pinned": false,
                    "unread": false,
                    "is_ai_managed": false,
                    "last_message_at": "2026-07-16T18:03:11.482Z",
                    "last_inbound_at": "2026-07-16T18:03:11.482Z",
                    "last_outbound_at": "2026-07-16T18:03:11.482Z",
                    "last_human_outbound_at": "2026-07-16T18:03:11.482Z",
                    "created_at": "2026-07-16T18:03:11.482Z"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The body was not JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "invalid_request"
                          ],
                          "description": "The body was not JSON."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not. The key is read-only and this endpoint writes. Mint a full-access key; the scope is fixed when a key is created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No thread with that id in this shop.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "not_found"
                          ],
                          "description": "No thread with that id in this shop."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "No verb was given, more than one was, or the named teammate's role does not grant inbox access.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "internal_error"
                          ],
                          "description": "No verb was given, more than one was, or the named teammate's role does not grant inbox access."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tasks": {
      "get": {
        "operationId": "list-tasks",
        "summary": "List tasks",
        "description": "The shop's to-do queue in the order it is worked: OPEN first (soonest due, undated last, then newest), then finished (most recently cleared first). That ordering answers two questions in one list — what is next, and what did we just clear.\n\nA Service VIN task is anchored to a conversation AND a customer AND a job AND the message it came out of, so a to-do that reads \"call them back about the price\" still carries everything needed to act on it.\n\n`?overdue=true` overrides `?status=`: an overdue FINISHED task is a contradiction, so the lens wins rather than AND-ing into an always-empty result.",
        "tags": [
          "Tasks"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "`done` covers completed and cancelled; `all` is both blocks.",
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "done",
                "all"
              ],
              "default": "open"
            }
          },
          {
            "name": "assigned_to",
            "in": "query",
            "required": false,
            "description": "Only this teammate's tasks.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "conversation_id",
            "in": "query",
            "required": false,
            "description": "Only tasks filed against this thread.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "overdue",
            "in": "query",
            "required": false,
            "description": "`true` for open tasks past their due date. Overrides `status`.",
            "schema": {
              "type": "string",
              "enum": [
                "true"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many to return, 1-100.",
            "schema": {
              "type": "integer",
              "default": 25,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "How many to skip. Pass `meta.next_offset` from the previous response to continue.",
            "schema": {
              "type": "integer",
              "default": "0"
            }
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "A page of tasks, with `meta.total`, `meta.omitted` and `meta.next_offset`. Answer \"how much is on our list\" from `meta.total`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Service VIN's id for the task."
                          },
                          "title": {
                            "type": "string",
                            "description": "What needs doing, in one line."
                          },
                          "notes": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Any detail behind the title."
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "open",
                              "done",
                              "canceled"
                            ],
                            "description": "`canceled` means it will not be done — the row stays, so the decision is visible."
                          },
                          "priority": {
                            "type": "string",
                            "enum": [
                              "low",
                              "normal",
                              "high"
                            ],
                            "description": "How urgent."
                          },
                          "due_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time",
                            "description": "When it is due. Null for an undated to-do, which sorts last."
                          },
                          "overdue": {
                            "type": "boolean",
                            "description": "Open and past its due date. Computed at read time, so it is always current."
                          },
                          "completed_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time",
                            "description": "When it was finished. Cleared on reopen, so a re-completed task reports the real finish."
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time",
                            "description": "When it was created."
                          },
                          "conversation": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid",
                            "description": "The inbox thread it belongs to."
                          },
                          "conversation_label": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Display name for that thread's contact."
                          },
                          "customer_id": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid",
                            "description": "The customer it is about."
                          },
                          "job_id": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid",
                            "description": "The job it hangs off."
                          },
                          "message_id": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid",
                            "description": "The thread line the task was created from — the customer's own words rather than a paraphrase."
                          },
                          "assigned_to": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid",
                            "description": "The teammate who owns it."
                          },
                          "assignee_name": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "That teammate's display name."
                          }
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "c6b0f2d8-5a41-4e93-87bd-2f4c9e1a6053",
                      "title": "Call Ben back with the ceramic price",
                      "notes": null,
                      "status": "open",
                      "priority": "high",
                      "due_at": "2026-07-16T18:03:11.482Z",
                      "overdue": true,
                      "completed_at": null,
                      "created_at": "2026-07-16T18:03:11.482Z",
                      "conversation": "a2c79d31-6b40-4e28-9f57-3d8b1a6c2e05",
                      "conversation_label": "Ben Carter",
                      "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                      "job_id": null,
                      "message_id": "5d1e9a73-2f48-4c60-b915-8e3a7c2d4f06",
                      "assigned_to": "e08c3a71-9d46-4b25-a1f7-63b90d5c284e",
                      "assignee_name": "Dana"
                    }
                  ],
                  "meta": {
                    "total": 7,
                    "omitted": 6,
                    "next_offset": 1
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "422": {
            "description": "`status` was not open, done or all.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "validation_error"
                          ],
                          "description": "`status` was not open, done or all."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "create-task",
        "summary": "Create a task",
        "description": "Adds one to-do. `title` is all that is required; everything else is an ANCHOR, and a task with anchors is worth several times one without.\n\nAnchor it to what caused it. `message_id` is the strongest — the thread line the task came out of, so whoever picks it up reads the customer's own words rather than a paraphrase. `conversation_id` files it against the thread, `customer_id` against the person, `job_id` against the car. They are independent; pass every one you know.\n\nAssigning PINGS somebody, and the target must be a teammate whose role grants inbox access. It is NOT idempotent: calling twice makes two tasks.",
        "tags": [
          "Tasks"
        ],
        "requestBody": {
          "required": true,
          "description": "The task, and whatever it is about.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "What needs doing, in one line. This is what the shop sees."
                  },
                  "notes": {
                    "type": "string",
                    "maxLength": 4000,
                    "description": "Detail behind the title."
                  },
                  "priority": {
                    "type": "string",
                    "enum": [
                      "low",
                      "normal",
                      "high"
                    ],
                    "description": "Default: `normal`. How urgent."
                  },
                  "due_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "ISO instant it is due. Resolve \"tomorrow\" against the SHOP's timezone before sending."
                  },
                  "conversation": {
                    "type": "string",
                    "format": "uuid",
                    "description": "The inbox thread it belongs to."
                  },
                  "customer_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "The customer it is about."
                  },
                  "job_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "The job it hangs off."
                  },
                  "message_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "The thread line that caused it."
                  },
                  "staff_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Hand it to this teammate. They are notified."
                  }
                },
                "required": [
                  "title"
                ]
              },
              "example": {
                "title": "Call Ben back with the ceramic price",
                "conversation": "a2c79d31-6b40-4e28-9f57-3d8b1a6c2e05",
                "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                "priority": "high"
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "201": {
            "description": "The created task.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Service VIN's id for the task."
                        },
                        "title": {
                          "type": "string",
                          "description": "What needs doing, in one line."
                        },
                        "notes": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Any detail behind the title."
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "open",
                            "done",
                            "canceled"
                          ],
                          "description": "`canceled` means it will not be done — the row stays, so the decision is visible."
                        },
                        "priority": {
                          "type": "string",
                          "enum": [
                            "low",
                            "normal",
                            "high"
                          ],
                          "description": "How urgent."
                        },
                        "due_at": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "When it is due. Null for an undated to-do, which sorts last."
                        },
                        "overdue": {
                          "type": "boolean",
                          "description": "Open and past its due date. Computed at read time, so it is always current."
                        },
                        "completed_at": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "When it was finished. Cleared on reopen, so a re-completed task reports the real finish."
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "When it was created."
                        },
                        "conversation": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The inbox thread it belongs to."
                        },
                        "conversation_label": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Display name for that thread's contact."
                        },
                        "customer_id": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The customer it is about."
                        },
                        "job_id": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The job it hangs off."
                        },
                        "message_id": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The thread line the task was created from — the customer's own words rather than a paraphrase."
                        },
                        "assigned_to": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The teammate who owns it."
                        },
                        "assignee_name": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "That teammate's display name."
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": {
                    "id": "c6b0f2d8-5a41-4e93-87bd-2f4c9e1a6053",
                    "title": "Call Ben back with the ceramic price",
                    "notes": null,
                    "status": "open",
                    "priority": "high",
                    "due_at": null,
                    "overdue": false,
                    "completed_at": null,
                    "created_at": "2026-07-16T18:03:11.482Z",
                    "conversation": "a2c79d31-6b40-4e28-9f57-3d8b1a6c2e05",
                    "conversation_label": "Ben Carter",
                    "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                    "job_id": null,
                    "message_id": null,
                    "assigned_to": null,
                    "assignee_name": null
                  }
                }
              }
            }
          },
          "400": {
            "description": "The body was not JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "invalid_request"
                          ],
                          "description": "The body was not JSON."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not. The key is read-only and this endpoint writes. Mint a full-access key; the scope is fixed when a key is created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "422": {
            "description": "`title` was missing, empty or over 200 characters.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "validation_error"
                          ],
                          "description": "`title` was missing, empty or over 200 characters."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "The named teammate's role does not grant inbox access, so the task would sit somewhere they cannot see it.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "internal_error"
                          ],
                          "description": "The named teammate's role does not grant inbox access, so the task would sit somewhere they cannot see it."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tasks/{id}": {
      "get": {
        "operationId": "get-task",
        "summary": "Get a task",
        "description": "One task and every anchor it carries. The anchors are the point: a to-do that says \"call them back about the price\" is useless on its own and complete with a thread id, and `message_id` is the exact sentence that caused it.\n\n`overdue` is computed against now rather than stored, so it is current when you read it. `completed_at` is cleared on reopen, so a task completed by mistake and finished properly later reports the real finish rather than the first one's.",
        "tags": [
          "Tasks"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The task's id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The task.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Service VIN's id for the task."
                        },
                        "title": {
                          "type": "string",
                          "description": "What needs doing, in one line."
                        },
                        "notes": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Any detail behind the title."
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "open",
                            "done",
                            "canceled"
                          ],
                          "description": "`canceled` means it will not be done — the row stays, so the decision is visible."
                        },
                        "priority": {
                          "type": "string",
                          "enum": [
                            "low",
                            "normal",
                            "high"
                          ],
                          "description": "How urgent."
                        },
                        "due_at": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "When it is due. Null for an undated to-do, which sorts last."
                        },
                        "overdue": {
                          "type": "boolean",
                          "description": "Open and past its due date. Computed at read time, so it is always current."
                        },
                        "completed_at": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "When it was finished. Cleared on reopen, so a re-completed task reports the real finish."
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "When it was created."
                        },
                        "conversation": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The inbox thread it belongs to."
                        },
                        "conversation_label": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Display name for that thread's contact."
                        },
                        "customer_id": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The customer it is about."
                        },
                        "job_id": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The job it hangs off."
                        },
                        "message_id": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The thread line the task was created from — the customer's own words rather than a paraphrase."
                        },
                        "assigned_to": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The teammate who owns it."
                        },
                        "assignee_name": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "That teammate's display name."
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": {
                    "id": "c6b0f2d8-5a41-4e93-87bd-2f4c9e1a6053",
                    "title": "Call Ben back with the ceramic price",
                    "notes": "He asked about the 5-year package.",
                    "status": "open",
                    "priority": "high",
                    "due_at": "2026-07-16T18:03:11.482Z",
                    "overdue": true,
                    "completed_at": null,
                    "created_at": "2026-07-16T18:03:11.482Z",
                    "conversation": "a2c79d31-6b40-4e28-9f57-3d8b1a6c2e05",
                    "conversation_label": "Ben Carter",
                    "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                    "job_id": "4a92c7f1-8d36-4b05-9e2a-1f6b3d8c50e7",
                    "message_id": "5d1e9a73-2f48-4c60-b915-8e3a7c2d4f06",
                    "assigned_to": "e08c3a71-9d46-4b25-a1f7-63b90d5c284e",
                    "assignee_name": "Dana"
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No task with that id in this shop.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "not_found"
                          ],
                          "description": "No task with that id in this shop."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "update-task",
        "summary": "Change one thing about a task",
        "description": "A VERB CALL. Send exactly ONE of `title`, `notes`, `priority`, `complete`, `reopen`, `cancel`, `staff_id`, `unassign`, `due_at`, `remove_due_date`, `link_conversation` or `unlink_conversation`. Two is refused, naming both — a single audit row cannot honestly describe two decisions.\n\nComplete, reopen and cancel are three different outcomes. `complete` means it was done; `cancel` means it will not be, and the row stays so \"we were going to and decided not to\" is still visible weeks later; `reopen` clears the completion stamp so a re-completed task reports the real finish.\n\nTHERE IS NO DELETE, here or anywhere on this API. A task is the record of something a shop said it would do, and `cancel` is the honest version of removing one.",
        "tags": [
          "Tasks"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The task's id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Exactly one change.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Rewrite the one-line title."
                  },
                  "notes": {
                    "type": "string",
                    "maxLength": 4000,
                    "description": "Replace the notes. An empty string clears them."
                  },
                  "priority": {
                    "type": "string",
                    "enum": [
                      "low",
                      "normal",
                      "high"
                    ],
                    "description": "Set urgency."
                  },
                  "complete": {
                    "type": "boolean",
                    "description": "Mark it done."
                  },
                  "reopen": {
                    "type": "boolean",
                    "description": "Put a done or cancelled task back to open."
                  },
                  "cancel": {
                    "type": "boolean",
                    "description": "It will not be done. The row stays."
                  },
                  "staff_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Hand it to this teammate. They are notified."
                  },
                  "unassign": {
                    "type": "boolean",
                    "description": "Take it off whoever holds it."
                  },
                  "due_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "ISO instant it is due, resolved against the shop's timezone."
                  },
                  "remove_due_date": {
                    "type": "boolean",
                    "description": "Clear the due date entirely."
                  },
                  "link_conversation": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Re-file it under this thread."
                  },
                  "unlink_conversation": {
                    "type": "boolean",
                    "description": "Detach it from its thread."
                  }
                }
              },
              "example": {
                "complete": true
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The task as it now stands.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Service VIN's id for the task."
                        },
                        "title": {
                          "type": "string",
                          "description": "What needs doing, in one line."
                        },
                        "notes": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Any detail behind the title."
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "open",
                            "done",
                            "canceled"
                          ],
                          "description": "`canceled` means it will not be done — the row stays, so the decision is visible."
                        },
                        "priority": {
                          "type": "string",
                          "enum": [
                            "low",
                            "normal",
                            "high"
                          ],
                          "description": "How urgent."
                        },
                        "due_at": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "When it is due. Null for an undated to-do, which sorts last."
                        },
                        "overdue": {
                          "type": "boolean",
                          "description": "Open and past its due date. Computed at read time, so it is always current."
                        },
                        "completed_at": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time",
                          "description": "When it was finished. Cleared on reopen, so a re-completed task reports the real finish."
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "When it was created."
                        },
                        "conversation": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The inbox thread it belongs to."
                        },
                        "conversation_label": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Display name for that thread's contact."
                        },
                        "customer_id": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The customer it is about."
                        },
                        "job_id": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The job it hangs off."
                        },
                        "message_id": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The thread line the task was created from — the customer's own words rather than a paraphrase."
                        },
                        "assigned_to": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "uuid",
                          "description": "The teammate who owns it."
                        },
                        "assignee_name": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "That teammate's display name."
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": {
                    "id": "c6b0f2d8-5a41-4e93-87bd-2f4c9e1a6053",
                    "title": "Call Ben back with the ceramic price",
                    "notes": null,
                    "status": "done",
                    "priority": "high",
                    "due_at": "2026-07-16T18:03:11.482Z",
                    "overdue": false,
                    "completed_at": "2026-07-16T18:03:11.482Z",
                    "created_at": "2026-07-16T18:03:11.482Z",
                    "conversation": "a2c79d31-6b40-4e28-9f57-3d8b1a6c2e05",
                    "conversation_label": "Ben Carter",
                    "customer_id": "b41d8e57-2c9a-4f6b-8d13-7a0e5c2f9b48",
                    "job_id": null,
                    "message_id": "5d1e9a73-2f48-4c60-b915-8e3a7c2d4f06",
                    "assigned_to": "e08c3a71-9d46-4b25-a1f7-63b90d5c284e",
                    "assignee_name": "Dana"
                  }
                }
              }
            }
          },
          "400": {
            "description": "The body was not JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "invalid_request"
                          ],
                          "description": "The body was not JSON."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not. The key is read-only and this endpoint writes. Mint a full-access key; the scope is fixed when a key is created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No task with that id in this shop.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "not_found"
                          ],
                          "description": "No task with that id in this shop."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "500": {
            "description": "No change was given, more than one was, or the named teammate's role does not grant inbox access.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "internal_error"
                          ],
                          "description": "No change was given, more than one was, or the named teammate's role does not grant inbox access."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/phone-numbers": {
      "get": {
        "operationId": "list-phone-numbers",
        "summary": "List the shop's phone numbers",
        "description": "The lines this shop sends and receives on, primary first. `is_primary` is the number a customer actually sees — the one automations, click-to-call and outbound texts use when nothing names a line.\n\n`is_sending` is whether a line can send AT ALL, which is not the same as the shop holding it: a number suspended for billing, or a reservation that never completed at the carrier, is a real row that will not carry a text. Released numbers never appear, and neither does an abandoned purchase.\n\n`meta.messaging_service` is set when the shop texts through a messaging service rather than a single line; the individual numbers under it still list normally.",
        "tags": [
          "Phone numbers"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many to return, 1-100. A shop holds a handful.",
            "schema": {
              "type": "integer",
              "default": 25,
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The shop's lines, primary first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Service VIN's id for the line."
                          },
                          "number": {
                            "type": "string",
                            "description": "The number itself, E.164."
                          },
                          "name": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "The owner's own label — \"Front desk\", \"Mobile crew\"."
                          },
                          "provider": {
                            "type": "string",
                            "description": "Who the line is held with."
                          },
                          "status": {
                            "type": "string",
                            "description": "`active` can send; `pending` is a reservation that was never bought; `suspended` is a billing hold. Released lines are not returned at all."
                          },
                          "country": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Two-letter country code."
                          },
                          "is_primary": {
                            "type": "boolean",
                            "description": "The number automations, click-to-call and outbound texts use when nothing names a line — the one a customer sees."
                          },
                          "is_sending": {
                            "type": "boolean",
                            "description": "Whether the line can actually send. Not the same as holding it: a suspended line is held and cannot carry a text."
                          },
                          "purchased_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time",
                            "description": "When the shop bought it."
                          }
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "data": [
                    {
                      "id": "2f7d4c91-8b03-45e6-a17c-9d5028f3b64a",
                      "number": "+14035557890",
                      "name": "Front desk",
                      "provider": "twilio",
                      "status": "active",
                      "country": "CA",
                      "is_primary": true,
                      "is_sending": true,
                      "purchased_at": "2026-07-16T18:03:11.482Z"
                    }
                  ],
                  "meta": {
                    "messaging_service": null,
                    "total": 1,
                    "omitted": 0
                  }
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "unauthorized"
                          ],
                          "description": "The key is missing, malformed, unknown, revoked, or past its expiry date. Unknown and revoked share one message on purpose, so a probe learns nothing; an expired key says so, since only its holder can ever see that."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "plan_lapsed"
                          ],
                          "description": "The Service VIN account behind this key has no active subscription — its free trial ended, its plan was canceled, or a payment failed past its retry window. The shop owner reactivates it under Settings → Plan & billing; retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "org_suspended"
                          ],
                          "description": "The Service VIN account behind this key is suspended. Billing or support resolves it — retrying will not."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "description": "More than 120 requests in 60 seconds on this key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "enum": [
                            "rate_limited"
                          ],
                          "description": "More than 120 requests in 60 seconds on this key."
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable detail, safe to log."
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "error"
                  ]
                }
              }
            }
          }
        }
      }
    }
  }
}