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

# PATCH /v1/users/:userId/characters/:characterId — Edit

> Partially update a character's biographical fields and avatar assets. All fields optional. Editing approved characters requires ADMINISTRATOR or DEVELOPER permission.

Use this endpoint to update an existing in-game character's biographical data. All body fields are optional — you only need to include the fields you want to change. In addition to text fields, you can upload new avatar image files (avatar, signature, full-body PNG, and 3D GLB) as a `multipart/form-data` request. The endpoint also accepts 3D camera and bounding-box metadata via a JSON string in the `avatar3D` field.

<Warning>
  Characters that have been **approved** cannot be edited. Attempting to update an approved character without `ADMINISTRATOR` or `DEVELOPER` permissions will return a `403 Forbidden` error. If you need to make changes after submission, [cancel the submission](/api-reference/characters/cancel-character) first to return the character to `draft` status.
</Warning>

<Note>
  This endpoint is rate-limited to **5 requests per minute**. The request must be sent as `multipart/form-data` when uploading files. If you are only updating text fields, you may send a standard `application/json` body or nest the data inside a `data` JSON string field in the form.
</Note>

## Endpoint

```text theme={null}
PATCH https://api.cacolombia.com/v1/users/:userId/characters/:characterId
```

## Path Parameters

<ParamField path="userId" type="string" required>
  The Snowflake ID of the user who owns the character. Must match the authenticated user's ID.
</ParamField>

<ParamField path="characterId" type="string" required>
  The Snowflake ID of the character to update.
</ParamField>

## Query Parameters

<ParamField query="signature" type="string">
  Pass `true` to include the character's `signatureData` field in the response after update. Omit or pass any other value to exclude it.
</ParamField>

## Request Body

All fields are optional. Send as `multipart/form-data` when uploading files, or as `application/json` for text-only updates.

<ParamField body="firstNames" type="string">
  Updated first name(s). Must be at least 2 characters long.
</ParamField>

<ParamField body="lastNames" type="string">
  Updated last name(s). Must be at least 2 characters long.
</ParamField>

<ParamField body="age" type="number">
  Updated age in years.
</ParamField>

<ParamField body="height" type="number">
  Updated height in centimetres.
</ParamField>

<ParamField body="gender" type="string">
  Updated gender. Must be exactly `Masculino` or `Femenino`.
</ParamField>

<ParamField body="bloodType" type="string">
  Updated blood type. Must be one of: `O+`, `O-`, `A+`, `A-`, `B+`, `B-`, `AB+`, `AB-`.
</ParamField>

<ParamField body="nationality" type="string">
  Updated nationality name. Must be a valid nationality from the CA Colombia platform list.
</ParamField>

<ParamField body="dob" type="string">
  Updated date of birth as an ISO 8601 date string (e.g. `1996-04-15`).
</ParamField>

<ParamField body="avatar" type="file">
  A PNG image file to use as the character's avatar. Upload as a form field named `avatar`.
</ParamField>

<ParamField body="signature" type="file">
  A PNG image file to use as the character's signature. Upload as a form field named `signature`.
</ParamField>

<ParamField body="fullBody" type="file">
  A PNG image file for the character's full-body reference. Upload as a form field named `fullBody`.
</ParamField>

<ParamField body="avatar3dGlb" type="file">
  A GLB file for the character's 3D avatar model. Upload as a form field named `avatar3dGlb`.
</ParamField>

<ParamField body="avatar3D" type="string">
  A JSON string containing 3D camera and bounding-box metadata. Must conform to the structure below.

  <Expandable title="avatar3D JSON structure">
    ```json theme={null}
    {
      "camera": {
        "position": { "x": 0.0, "y": 4.5, "z": 12.3 },
        "direction": { "x": 0.0, "y": -0.2, "z": -1.0 },
        "fov": 45.0
      },
      "aabb": {
        "min": { "x": -1.2, "y": 0.0, "z": -0.5 },
        "max": { "x": 1.2, "y": 5.8, "z": 0.5 }
      }
    }
    ```
  </Expandable>
</ParamField>

## Response

Returns `200 OK` with the full updated character object.

<ResponseField name="characterId" type="string">
  The character's unique Snowflake ID.
</ResponseField>

<ResponseField name="userId" type="string">
  The Snowflake ID of the user who owns this character.
</ResponseField>

<ResponseField name="firstNames" type="string">
  The character's first name(s).
</ResponseField>

<ResponseField name="lastNames" type="string">
  The character's last name(s).
</ResponseField>

<ResponseField name="age" type="number">
  The character's age in years.
</ResponseField>

<ResponseField name="height" type="number">
  The character's height in centimetres.
</ResponseField>

<ResponseField name="gender" type="string">
  The character's gender.
</ResponseField>

<ResponseField name="bloodType" type="string">
  The character's blood type.
</ResponseField>

<ResponseField name="nationality" type="object">
  An object describing the character's nationality with `nombre`, `abrev`, and `lugar` fields.
</ResponseField>

<ResponseField name="dob" type="string">
  The character's date of birth in `DD/MM/YYYY` format.
</ResponseField>

<ResponseField name="avatarHash" type="string | null">
  Hash identifier for the character's avatar image, updated if a new file was uploaded.
</ResponseField>

<ResponseField name="idCardHash" type="string | null">
  Hash identifier for the character's generated ID card image.
</ResponseField>

<ResponseField name="fullBodyHash" type="string | null">
  Hash identifier for the character's full-body image, updated if a new file was uploaded.
</ResponseField>

<ResponseField name="avatar3dHash" type="string | null">
  Hash identifier for the character's 3D GLB model, updated if a new file was uploaded.
</ResponseField>

<ResponseField name="avatar3dCamera" type="object | null">
  Camera metadata for the 3D avatar, updated if `avatar3D` was provided.
</ResponseField>

<ResponseField name="avatar3dAABB" type="object | null">
  Bounding box metadata for the 3D avatar, updated if `avatar3D` was provided.
</ResponseField>

<ResponseField name="idStatus" type="string">
  The character's current ID card approval status.
</ResponseField>

<ResponseField name="wallet" type="object | null">
  The character's in-game wallet, or `null` if none exists.
</ResponseField>

<ResponseField name="signatureData" type="string">
  The character's signature data. Only present when `signature=true` is passed.
</ResponseField>

<ResponseField name="createdAt" type="string">
  ISO 8601 timestamp of when the character was created.
</ResponseField>

<ResponseField name="updatedAt" type="string">
  ISO 8601 timestamp of when the character was last updated.
</ResponseField>

## Example Request (JSON — text fields only)

```bash theme={null}
curl -X PATCH "https://api.cacolombia.com/v1/users/112233445566778899/characters/998877665544332211" \
  -H "Authorization: Bearer <your_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "firstNames": "Carlos Andrés",
    "age": 29
  }'
```

## Example Request (multipart — with avatar upload)

```bash theme={null}
curl -X PATCH "https://api.cacolombia.com/v1/users/112233445566778899/characters/998877665544332211" \
  -H "Authorization: Bearer <your_token>" \
  -F 'data={"firstNames":"Carlos Andrés","age":29}' \
  -F 'avatar=@/path/to/avatar.png'
```

## Example Response

```json theme={null}
{
  "characterId": "998877665544332211",
  "userId": "112233445566778899",
  "firstNames": "Carlos Andrés",
  "lastNames": "Reyes Gómez",
  "age": 29,
  "height": 175,
  "gender": "Masculino",
  "bloodType": "O+",
  "nationality": {
    "nombre": "Colombiano",
    "abrev": "COL",
    "lugar": "Colombia"
  },
  "dob": "15/04/1996",
  "avatarHash": "newHash123abc",
  "idCardHash": null,
  "fullBodyHash": null,
  "avatar3dHash": null,
  "avatar3dCamera": null,
  "avatar3dAABB": null,
  "idStatus": "draft",
  "wallet": null,
  "createdAt": "2024-01-10T14:30:00.000Z",
  "updatedAt": "2024-06-15T11:45:00.000Z"
}
```

## Error Responses

| Status | Error                  | Description                                                                                          |
| ------ | ---------------------- | ---------------------------------------------------------------------------------------------------- |
| `401`  | `Unauthorized`         | No valid authentication token was provided.                                                          |
| `403`  | `Forbidden`            | The authenticated user does not match the `userId` in the path.                                      |
| `403`  | `Forbidden`            | The character has already been approved and cannot be edited without elevated permissions.           |
| `400`  | `Invalid form of body` | One or more fields failed validation. The response includes a `details` field describing each issue. |
| `404`  | `Unknown User`         | No user was found with the given `userId`.                                                           |
| `404`  | `Unknown Character`    | No character was found with the given `characterId` belonging to this user.                          |
