---
title: "Update an existing contractor service listing"
method: PUT
path: "/services/{id}"
tags: ["Services"]
---

# Update an existing contractor service listing

`PUT /services/{id}`

## Request

- Base URL: `https://api.purplegrain.com/api/v1`
- URL: `https://api.purplegrain.com/api/v1/services/{id}`
- Auth: HTTP bearer

Change the service listing identified by id, such as its name, description, active or inactive status, quoted cost and currency, service radius, tags or related place. Send only the requested changes in data; omitted fields stay unchanged. Read the listing first and confirm the changes with the person. The caller must be able to act for the listing's owner, and an MCP connection must allow writes. Returns the updated service. This does not book a contractor, send a message or take payment. Use updateServiceImage for the listing's photo.

## Path parameters

- `id` string, required

## Query parameters

- `include` string

## Request body

- ServiceUpdateModelAttributes: Flat attributes-adapter request body (Content-Type application/json). Attribute fields and relationships live directly under `data` (no nested `attributes` / `relationships` envelopes). Each relationship is a resource identifier object ({ id, type }). Equivalent JSON:API (nested) shape: `ServiceUpdateModel` sent as application/vnd.api+json.
  - `data` object, required
    - `name` string
    - `slug` string, nullable
    - `description` string, nullable
    - `status` 'active' | 'inactive', nullable
    - `cost` string, nullable
    - `currency` string, nullable
    - `radius` integer, nullable
    - `tags` string[], nullable: Hashtag-style labels (they work like Twitter hashtags) — free-form lowercase tokens stored without a leading hash, e.g. ["slashing", "north-paddock"]. Reusing a tag groups records together, and the /tasks/search and /services/search term parameter matches tags case-insensitively, so a tag aggregates everything labelled with it. Send an empty array to clear every tag (null is accepted and stored as an empty array).
    - `owner` object, nullable
      - `id` string, nullable
      - `type` 'user' | 'organization', nullable
    - `place` object, nullable
      - `id` string, nullable
      - `type` 'city' | 'address', nullable
    - `category` object, nullable
      - `id` string, nullable
      - `type` string, nullable

## Response `200`

Update. When the `include` query parameter is used, the response may contain an `included` array (JSON:API) or inlined related resources (application/json).

- ServicesShowResponseAttributes
  - `data` ServiceModelAttributes: Service in attributes-adapter shape (Accept application/json); fields at top level.
    - `id` string
    - `type` string
    - `slug` string
    - `name` string
    - `status` 'active' | 'inactive'
    - `cost` string, nullable
    - `currency` string, nullable
    - `description` string, nullable
    - `tags` string[]: Hashtag-style labels (they work like Twitter hashtags) — free-form lowercase tokens stored without a leading hash, e.g. ["slashing", "north-paddock"]. Reusing a tag groups records together, and the /tasks/search and /services/search term parameter matches tags case-insensitively, so a tag aggregates everything labelled with it. Always an array — the API never returns null.
    - `radius` integer, nullable
    - `url` string
    - `image_url` string, nullable
    - `image_thumb_url` string, nullable
    - `updated_at` string, date-time
    - `created_at` string, date-time
    - `city` object: Inlined when include=city
    - `place` object: Inlined when include=place
    - `owner` object: Inlined when include=owner
    - `category` object: Inlined when include=category
    - `location` object: Inlined when include=location

## Other responses

- `422`: Errors

---

[API](https://skmtc.dev/purplegrain/apis/purple-grain-api.md) · [All operations](https://skmtc.dev/purplegrain/apis/purple-grain-api/llms.txt) · [OpenAPI document](https://skmtc.dev/purplegrain/apis/purple-grain-api/revisions/06540345bbbc?raw)
