> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lmrp.uk/llms.txt
> Use this file to discover all available pages before exploring further.

# Edit a unit

> **Permission:** `cad.units.manage`. Requires `cad.view` as well, like every Control endpoint.

**Access:** Browser session, or a service credential holding the permission as a scope.

Replaces callsign, agency, type and the whole crew list. Members left out are ended; new ones are added. Emptying the crew takes the unit off duty and withdraws it from any incident. Adding crew to an off-duty unit makes it `AVAILABLE`. Records `UNIT_UPDATED` with before and after.



## OpenAPI

````yaml /api-reference/openapi.json post /cad/units/{id}/edit
openapi: 3.1.0
info:
  title: Argus API
  version: 0.1.0
  summary: The HTTP API behind the Argus web application.
  description: >-
    Argus is the operations platform for the UK London Mayfair ER:LC community.
    This document describes the API its own web application uses.


    **This is an internal application API.** It is not a stable public API:
    paths, fields and behaviour can change with any release, there is no
    versioning, and browser requests are tied to the application's own origin.
    Scoped service credentials exist for the community's own integrations.


    All paths are relative to `/api` on the deployment's origin. Responses are
    JSON, never cacheable, and carry an `X-Request-Id` header.
servers:
  - url: http://localhost:3000/api
    description: Local development
  - url: '{origin}/api'
    description: A deployment. `origin` is that deployment's `APP_URL`.
    variables:
      origin:
        default: https://argus.example.org
        description: The application's public origin, with no trailing slash.
security: []
tags:
  - name: Authentication
    description: >-
      Discord sign-in, Roblox account linking, the current user, and temporary
      Developer Access.
  - name: CAD Incidents
    description: >-
      Control's incidents: creation, editing, closure, and dispatching units to
      them.
  - name: CAD Units
    description: Control's view of operational units and their crew.
  - name: CAD Calls
    description: Incoming calls and how they become, or join, incidents.
  - name: CAD Events
    description: The append-only operational history.
  - name: MDT
    description: >-
      Self-service for the people crewing a unit: booking on and off, joining a
      unit, and changing its status.
  - name: Civilians
    description: 'The civilian portal: a member''s own characters, licences and vehicles.'
  - name: PNC Lookup
    description: >-
      Searching people and vehicles, full records, record history and official
      vehicle status.
  - name: PNC Licences
    description: Official changes to driving licences.
  - name: PNC Records
    description: Official records attached to people.
  - name: PNC Warrants
    description: Warrants and their lifecycle.
  - name: PNC Markers
    description: Markers and BOLOs on people and vehicles.
  - name: Staff
    description: Staff profiles and role membership.
  - name: Shifts
    description: Staff shifts.
  - name: Sessions
    description: Operational roleplay sessions.
  - name: Moderation
    description: Warnings, kicks and bans, with their delivery state.
  - name: Audit
    description: The append-only audit log.
  - name: Administration
    description: Accounts, roles and service credentials.
  - name: ERLC
    x-displayName: ER:LC
    description: Live data from the ER:LC private server.
paths:
  /cad/units/{id}/edit:
    post:
      tags:
        - CAD Units
      summary: Edit a unit
      description: >-
        **Permission:** `cad.units.manage`. Requires `cad.view` as well, like
        every Control endpoint.


        **Access:** Browser session, or a service credential holding the
        permission as a scope.


        Replaces callsign, agency, type and the whole crew list. Members left
        out are ended; new ones are added. Emptying the crew takes the unit off
        duty and withdraws it from any incident. Adding crew to an off-duty unit
        makes it `AVAILABLE`. Records `UNIT_UPDATED` with before and after.
      operationId: editUnit
      parameters:
        - name: id
          in: path
          required: true
          schema:
            $ref: '#/components/schemas/Id'
          description: Unit ID.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UnitEditInput'
            example:
              callsign: MO12
              agencyCode: MET
              type: RESPONSE
              crew:
                - cmg5x1k2a0000l508a1b2c3d4
                - cmg5x1k2a0002l508b7c8d9e0
              version: 1
      responses:
        '200':
          description: Success.
          headers:
            X-Request-Id:
              $ref: '#/components/headers/RequestId'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/CadUnit'
                required:
                  - data
              example:
                data:
                  id: cmg5z2unt000al508unt00001
                  callsign: MO12
                  agencyCode: MET
                  type: RESPONSE
                  status: AVAILABLE
                  incidentId: null
                  version: 2
                  createdAt: '2026-10-06T19:30:00.000Z'
                  updatedAt: '2026-10-06T19:42:10.000Z'
                  crew:
                    - id: cmg5z3crw000bl508crw00001
                      unitId: cmg5z2unt000al508unt00001
                      identifier: Olivia Officer
                      userId: cmg5x1k2a0000l508a1b2c3d4
                      joinedAt: '2026-10-06T19:30:00.000Z'
                      leftAt: null
                      user:
                        id: cmg5x1k2a0000l508a1b2c3d4
                        displayName: Olivia Officer
                        discord:
                          id: '254781093445672960'
                          username: olivia.officer
                          avatar: null
                        roblox:
                          id: '4821093375'
                          username: OliviaOfficer
                        staff:
                          id: cmg5x1k2a0001l5089f8e7d6c
                          active: true
                    - id: cmg5z3crw000cl508crw00002
                      unitId: cmg5z2unt000al508unt00001
                      identifier: Ben Baker
                      userId: cmg5x1k2a0002l508b7c8d9e0
                      joinedAt: '2026-10-06T19:42:10.000Z'
                      leftAt: null
                      user:
                        id: cmg5x1k2a0002l508b7c8d9e0
                        displayName: Ben Baker
                        discord: null
                        roblox: null
                        staff:
                          id: cmg5x1k2a000ol508staff0002
                          active: true
                  incident: null
        '400':
          description: >-
            `INVALID_INPUT`: a parameter or body field fails validation;
            `details` lists each problem.


            `INVALID_JSON`: the body is missing or is not valid JSON.
          headers:
            X-Request-Id:
              $ref: '#/components/headers/RequestId'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: INVALID_INPUT
                  message: Request validation failed.
                  details:
                    - path:
                        - callsign
                      message: Invalid input
                requestId: 3f1c9d5e-7a42-4f0b-9c1e-8b6d2a4e5f70
        '401':
          $ref: '#/components/responses/Unauthenticated'
        '403':
          description: >-
            `FORBIDDEN`: the caller lacks `cad.units.manage`.


            `STAFF_REQUIRED`: a new crew member is not active staff.


            `INVALID_ORIGIN`: a browser request whose `Origin` is not the
            application's own.


            `ACCOUNT_DISABLED`: the account is suspended or disabled.
          headers:
            X-Request-Id:
              $ref: '#/components/headers/RequestId'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: FORBIDDEN
                  message: 'Permission required: cad.units.manage.'
                requestId: 3f1c9d5e-7a42-4f0b-9c1e-8b6d2a4e5f70
        '404':
          description: '`NOT_FOUND`: no such unit.'
          headers:
            X-Request-Id:
              $ref: '#/components/headers/RequestId'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: NOT_FOUND
                  message: CAD record not found.
                requestId: 3f1c9d5e-7a42-4f0b-9c1e-8b6d2a4e5f70
        '409':
          description: >-
            `CAD_CONFLICT`: the `version` is stale, or a new crew member is
            already crewed elsewhere.


            `CONFLICT`: the callsign is taken, or a concurrent change won.
          headers:
            X-Request-Id:
              $ref: '#/components/headers/RequestId'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  code: CAD_CONFLICT
                  message: Unit changed. Refresh before saving.
                requestId: 3f1c9d5e-7a42-4f0b-9c1e-8b6d2a4e5f70
        '429':
          $ref: '#/components/responses/RateLimited'
        default:
          $ref: '#/components/responses/UnexpectedError'
      security:
        - sessionCookie: []
        - serviceCredential: []
components:
  schemas:
    Id:
      type: string
      minLength: 1
      maxLength: 64
      pattern: ^[a-zA-Z0-9_-]+$
      description: Argus record identifier.
    UnitEditInput:
      type: object
      properties:
        callsign:
          type: string
          minLength: 1
          maxLength: 24
          pattern: ^[a-zA-Z0-9 -]+$
          description: Trimmed and stored in capitals. Unique across units.
        agencyCode:
          type: string
          minLength: 1
          maxLength: 24
          pattern: ^[a-zA-Z0-9_-]+$
          description: Trimmed and stored in capitals, for example `MET`, `LAS` or `LFB`.
        type:
          type: string
          enum:
            - RESPONSE
            - PATROL
            - TRAFFIC
            - FIRE
            - AMBULANCE
            - SUPERVISOR
            - SPECIALIST
        crew:
          type: array
          items:
            $ref: '#/components/schemas/Id'
          maxItems: 8
          uniqueItems: true
          description: >-
            Argus user IDs, never typed names. Each must be active staff and not
            crewed elsewhere. Empty means the unit is off duty.
        version:
          type: integer
          minimum: 1
          description: The `version` you last read. A mismatch returns 409.
      required:
        - callsign
        - agencyCode
        - type
        - crew
        - version
      additionalProperties: false
    CadUnit:
      type: object
      properties:
        id:
          $ref: '#/components/schemas/Id'
        callsign:
          type: string
        agencyCode:
          type: string
        type:
          type: string
          enum:
            - RESPONSE
            - PATROL
            - TRAFFIC
            - FIRE
            - AMBULANCE
            - SUPERVISOR
            - SPECIALIST
        status:
          type: string
          enum:
            - AVAILABLE
            - ASSIGNED
            - EN_ROUTE
            - ON_SCENE
            - BUSY
            - UNAVAILABLE
            - OFF_DUTY
        incidentId:
          anyOf:
            - $ref: '#/components/schemas/Id'
            - type: 'null'
        version:
          type: integer
          description: >-
            Optimistic concurrency token. Send the latest value with every
            change.
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        crew:
          type: array
          items:
            $ref: '#/components/schemas/CadCrewMember'
          description: Active memberships only, oldest first.
        incident:
          anyOf:
            - $ref: '#/components/schemas/CadIncident'
            - type: 'null'
          description: The incident the unit is assigned to.
      required:
        - id
        - callsign
        - agencyCode
        - type
        - status
        - incidentId
        - version
        - createdAt
        - updatedAt
        - crew
        - incident
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              description: Stable machine-readable code.
            message:
              type: string
            details:
              description: >-
                Present on some errors. Validation failures carry an array of
                `{path, message}`; ER:LC failures carry `{availability:
                "unavailable"}`.
          required:
            - code
            - message
        requestId:
          type: string
          format: uuid
          description: >-
            Also sent as the `X-Request-Id` header. Quote it when reporting a
            problem.
      required:
        - error
        - requestId
    CadCrewMember:
      type: object
      properties:
        id:
          $ref: '#/components/schemas/Id'
        unitId:
          $ref: '#/components/schemas/Id'
        identifier:
          type: string
          description: Display-name snapshot taken when the membership began.
        userId:
          anyOf:
            - $ref: '#/components/schemas/Id'
            - type: 'null'
        joinedAt:
          type: string
          format: date-time
        leftAt:
          type:
            - string
            - 'null'
          format: date-time
          description: Null while the membership is active.
        user:
          anyOf:
            - $ref: '#/components/schemas/CrewIdentity'
            - type: 'null'
          description: Null only for legacy free-text history.
      required:
        - id
        - unitId
        - identifier
        - userId
        - joinedAt
        - leftAt
        - user
    CadIncident:
      type: object
      properties:
        id:
          $ref: '#/components/schemas/Id'
        number:
          type: integer
          description: Sequential. Displayed as `CAD-000142`.
        status:
          type: string
          enum:
            - OPEN
            - CLOSED
        priority:
          type: string
          enum:
            - IMMEDIATE
            - URGENT
            - ROUTINE
            - LOW
        type:
          type: string
        location:
          type: string
        description:
          type: string
        controlNotes:
          type: string
        version:
          type: integer
          description: Optimistic concurrency token.
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        closedAt:
          type:
            - string
            - 'null'
          format: date-time
      required:
        - id
        - number
        - status
        - priority
        - type
        - location
        - description
        - controlNotes
        - version
        - createdAt
        - updatedAt
        - closedAt
    CrewIdentity:
      type: object
      properties:
        id:
          $ref: '#/components/schemas/Id'
        displayName:
          type: string
        discord:
          type:
            - object
            - 'null'
          properties:
            id:
              type: string
            username:
              type: string
            avatar:
              type:
                - string
                - 'null'
          required:
            - id
            - username
            - avatar
        roblox:
          type:
            - object
            - 'null'
          properties:
            id:
              $ref: '#/components/schemas/RobloxId'
            username:
              type: string
          required:
            - id
            - username
        staff:
          type:
            - object
            - 'null'
          properties:
            id:
              $ref: '#/components/schemas/Id'
            active:
              type: boolean
          required:
            - id
            - active
      required:
        - id
        - displayName
        - discord
        - roblox
        - staff
    RobloxId:
      type: string
      pattern: ^[1-9][0-9]{0,19}$
      description: Roblox user ID, as a string.
  headers:
    RequestId:
      schema:
        type: string
        format: uuid
      description: Identifies this request in server logs.
    RetryAfter:
      schema:
        type: integer
        minimum: 1
      description: Seconds to wait before trying again.
  responses:
    Unauthenticated:
      description: >-
        `UNAUTHENTICATED`: no session cookie, or an invalid, expired or revoked
        service credential.


        `SESSION_EXPIRED`: the session has ended.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: UNAUTHENTICATED
              message: Sign in to continue.
            requestId: 3f1c9d5e-7a42-4f0b-9c1e-8b6d2a4e5f70
    RateLimited:
      description: >-
        `RATE_LIMITED`: more than 180 reads or 60 writes in a minute for this
        caller.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: RATE_LIMITED
              message: Too many requests.
            requestId: 3f1c9d5e-7a42-4f0b-9c1e-8b6d2a4e5f70
    UnexpectedError:
      description: >-
        Any other failure, in the same error envelope: `INTERNAL_ERROR` (500),
        `METHOD_NOT_ALLOWED` (405), `BODY_TOO_LARGE` (413, over 16 KiB) or
        `UNSUPPORTED_MEDIA_TYPE` (415, body not sent as `application/json`).
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: INTERNAL_ERROR
              message: The request could not be completed.
            requestId: 3f1c9d5e-7a42-4f0b-9c1e-8b6d2a4e5f70
  securitySchemes:
    sessionCookie:
      type: apiKey
      in: cookie
      name: __Host-argus-session
      description: >-
        The opaque session cookie set by Discord sign-in. Named `argus-session`
        outside production. HttpOnly, so scripts cannot read it; same-origin
        requests send it automatically. Requests other than GET must also carry
        an `Origin` header equal to the application's own origin.
    serviceCredential:
      type: http
      scheme: bearer
      bearerFormat: argus_ followed by 43 URL-safe characters
      description: >-
        A scoped credential issued by an administrator for the community's own
        integrations. Its scopes are permission keys. It expires within 90 days,
        can be revoked, and cannot call endpoints that need a signed-in user.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.