# ServiceUser

A *ServiceUser* is an end-user of your product who signed up through [ServiceLogin](/api/reference/cma/service-login.md), that is, a member account. It is a separate identity from a Weegloo platform account (the Weegloo User who logs in to the content studio), and a *ServiceUser*'s token authenticates against ACMA/ACDA.

A *ServiceUser* is created when a member signs up directly through *ServiceLogin*. For that reason this API has no create endpoint, only reads and a few updates made by an administrator (a Weegloo User).

## Resource structure {#resource-structure}

The following is the single-read response for one *ServiceUser*. Together with `sys` (system properties), it has the body properties that hold the member's display info and permission settings: `nickname`, `avatarUrl`, `roleOverride`, and `enableLogin`.

```json
{
  "sys": {
    "id": "3trmXRM3RqbgSnifyg7PSusr01Ex",
    "type": "ServiceUser",
    "space": { "sys": { "id": "tcq4V2Xb", "type": "Refer", "targetType": "Space" } },
    "provider": "google",
    "email": "buyer@example.com",
    "createdAt": "2026-06-18T12:50:00.000Z",
    "updatedAt": "2026-06-18T12:50:00.000Z"
  },
  "nickname": "Regular shopper",
  "avatarUrl": "https://lh3.example.com/a/buyer-avatar",
  "roleOverride": null,
  "enableLogin": true
}
```

Key properties:

- `sys.email`: The email address the member used to sign up. Together with `sys.provider`, it shows which account they signed up with.
- `sys.provider`: The OAuth provider used to sign up (for example, `google`).
- `roleOverride`: The `Refer` you put in to give a different *ServiceUserRole* to this member alone. When it is empty (`null`), the member follows *ServiceLogin*'s default role.

## System properties (sys) {#system-properties-sys}

Every *ServiceUser* carries common system properties in the `sys` object. `space` is in the `Refer` shape (`{ "sys": { "id", "type": "Refer", "targetType" } }`).

| Property | Type | Description |
|---|---|---|
| `id` | string | Unique resource identifier. |
| `type` | string | Resource kind. For a *ServiceUser* this is always `"ServiceUser"`. |
| `space` | Refer&lt;Space&gt; | The *Space* this *ServiceUser* belongs to. |
| `provider` | string | The OAuth provider used to sign up (for example, `google`). |
| `email` | string | The email address used to sign up. |
| `createdAt` | string (date-time) | Sign-up (creation) time. |
| `updatedAt` | string (date-time) | Last update time. |

Because a *ServiceUser* is a resource a member creates by their own sign-up, its `sys` has no `createdBy`, `updatedBy`, or `version`, unlike other CMA resources. Since there is no `version`, updates (`PUT`, `PATCH`) also do not send the `X-Weegloo-Version` header. There is no publishing concept either, so there is no `publish`, `archive`, or `status`.

## Body properties {#body-properties}

| Property | Type | Description |
|---|---|---|
| `nickname` | string | The member's display name. |
| `avatarUrl` | string | Profile image address (optional). |
| `roleOverride` | Refer&lt;ServiceUserRole&gt; | A *ServiceUserRole* to give to this member alone (optional). When set, it takes precedence over *ServiceLogin*'s default role. |
| `enableLogin` | boolean | Whether login is allowed. Turning it off blocks this member's login. |

## Managing members {#managing-members}

A *ServiceUser* comes into being through sign-up. An administrator (a Weegloo User) can adjust the following two things with an update (`PUT`, `PATCH`).

- Set/clear `roleOverride`: Gives a different *ServiceUserRole* to one specific member only. Use it when you want to treat a single member differently, such as for a paid tier, a moderator, or a beta group. A `roleOverride` you set takes precedence over *ServiceLogin*'s `defaultRole`.
- Toggle `enableLogin`: Turning it off blocks that member's login.

Removing a member from the roster is done in the content studio. The steps, and what goes with them, are covered in [Managing service members](/operations/service/managing-members.md#removing-a-member).

To let one member handle resources created by other members, build a separate *ServiceUserRole* that carries that permission and set it on that member's `roleOverride`. What a member can reach is decided by the *ServiceUserRole* applied to them. When a rule's `createdBy` filter is set to `:self`, that action targets only what the member created themselves; when the filter is left out, the action targets what other members created as well. Building the two roles separately is covered in [ServiceUserRole](/api/reference/cma/service-user-role.md#admin-role).

## API {#api}

The base URL for all endpoints below is `https://cma.weegloo.com/v1`, and a Bearer token that authenticates against CMA is required in the `Authorization` header. Because a *ServiceUser* is a resource with no `version`, updates (`PUT`, `PATCH`) also do not send the `X-Weegloo-Version` header. There is no create endpoint (a member is created by sign-up).

**When you filter the list read by `sys.email`, use exact-match operators only** (`eq`, `ne`, `in`, `nin`). A member's address is stored encrypted, so on that representation you can only decide whether it is equal or not; `prefix` and the comparison operators return 0 results without an error. If you looked a member up by address and the result is empty, check the operator first. A search by part of an address cannot be done with this filter.

```api-endpoint
{
  "title": "List ServiceUsers",
  "method": "GET",
  "path": "/spaces/{spaceId}/service-users",
  "description": "Reads the ServiceUsers who signed up for one Space, page by page.",
  "responseStatus": 200,
  "baseUrl": "https://cma.weegloo.com/v1",
  "pathParameterSchema": {
    "spaceId": { "type": "string", "description": "The sys.id of the Space", "required": true }
  },
  "queryParameterSchema": {
    "limit": { "type": "integer", "description": "Number of items to return per page (1-100)", "default": 15 },
    "skip": { "type": "integer", "description": "Number of items to skip", "default": 0 },
    "next": { "type": "string", "description": "Next-page cursor (the value from links.next in the previous response)" },
    "prev": { "type": "string", "description": "Previous-page cursor (the value from links.prev in the previous response)" },
    "order": { "type": "string", "description": "Sort criteria. Multiple sorts separated by commas (e.g. sys.createdAt,sys.id)", "default": "sys.createdAt,sys.id" },
    "select": { "type": "string", "description": "Fields to include (sys.id,sys.createdAt) or exclude (-sys.id). Do not mix inclusion and exclusion." },
    "include": { "type": "integer", "description": "Related-resource inclusion level. 0=default, 1=related resources, 2=nested relations, 3=full", "default": 0 }
  },
  "additionalQueryParams": true,
  "requestHeaderSchema": {
    "Authorization": { "type": "string", "description": "Bearer token (CMA authentication)" }
  },
  "responseExample": {
    "sys": { "type": "TotalPageResponse" },
    "limit": 15,
    "totalCount": 1,
    "items": [
      {
        "sys": {
          "id": "3trmXRM3RqbgSnifyg7PSusr01Ex",
          "type": "ServiceUser",
          "space": { "sys": { "id": "tcq4V2Xb", "type": "Refer", "targetType": "Space" } },
          "provider": "google",
          "email": "buyer@example.com",
          "createdAt": "2026-06-18T12:50:00.000Z",
          "updatedAt": "2026-06-18T12:50:00.000Z"
        },
        "nickname": "Regular shopper",
        "avatarUrl": "https://lh3.example.com/a/buyer-avatar",
        "roleOverride": null,
        "enableLogin": true
      }
    ],
    "links": { "self": "/v1/spaces/tcq4V2Xb/service-users" }
  }
}
```

```api-endpoint
{
  "title": "Read a single ServiceUser",
  "method": "GET",
  "path": "/spaces/{spaceId}/service-users/{serviceUserId}",
  "description": "Reads one ServiceUser by sys.id.",
  "responseStatus": 200,
  "baseUrl": "https://cma.weegloo.com/v1",
  "pathParameterSchema": {
    "spaceId": { "type": "string", "description": "The sys.id of the Space", "required": true },
    "serviceUserId": { "type": "string", "description": "The sys.id of the ServiceUser", "required": true }
  },
  "queryParameterSchema": {
    "include": { "type": "integer", "description": "Related-resource inclusion level. 0=default, 1=related resources, 2=nested relations, 3=full", "default": 0 }
  },
  "requestHeaderSchema": {
    "Authorization": { "type": "string", "description": "Bearer token (CMA authentication)" }
  },
  "responseExample": {
    "sys": {
      "id": "3trmXRM3RqbgSnifyg7PSusr01Ex",
      "type": "ServiceUser",
      "space": { "sys": { "id": "tcq4V2Xb", "type": "Refer", "targetType": "Space" } },
      "provider": "google",
      "email": "buyer@example.com",
      "createdAt": "2026-06-18T12:50:00.000Z",
      "updatedAt": "2026-06-18T12:50:00.000Z"
    },
    "nickname": "Regular shopper",
    "avatarUrl": "https://lh3.example.com/a/buyer-avatar",
    "roleOverride": null,
    "enableLogin": true
  }
}
```

```api-endpoint
{
  "title": "Update a ServiceUser",
  "method": "PUT",
  "path": "/spaces/{spaceId}/service-users/{serviceUserId}",
  "description": "Replaces a ServiceUser's enableLogin and roleOverride. Use roleOverride to give a different ServiceUserRole to this member alone. Because the resource has no version, there is no X-Weegloo-Version header.",
  "responseStatus": 200,
  "baseUrl": "https://cma.weegloo.com/v1",
  "pathParameterSchema": {
    "spaceId": { "type": "string", "description": "The sys.id of the Space", "required": true },
    "serviceUserId": { "type": "string", "description": "The sys.id of the ServiceUser", "required": true }
  },
  "requestHeaderSchema": {
    "Authorization": { "type": "string", "description": "Bearer token (CMA authentication)" }
  },
  "requestBodySchema": {
    "type": "object",
    "required": ["enableLogin"],
    "properties": {
      "enableLogin": { "type": "boolean", "description": "Whether login is allowed" },
      "roleOverride": { "type": "object", "description": "The Refer of a ServiceUserRole to give to this member alone (optional). Takes precedence over ServiceLogin's default role." }
    },
    "example": {
      "enableLogin": true,
      "roleOverride": { "sys": { "id": "3trmXRLXeZN2RTHvVj3hFDN5546vbp", "type": "Refer", "targetType": "ServiceUserRole" } }
    }
  },
  "responseExample": {
    "sys": {
      "id": "3trmXRM3RqbgSnifyg7PSusr01Ex",
      "type": "ServiceUser",
      "space": { "sys": { "id": "tcq4V2Xb", "type": "Refer", "targetType": "Space" } },
      "provider": "google",
      "email": "buyer@example.com",
      "createdAt": "2026-06-18T12:50:00.000Z",
      "updatedAt": "2026-06-18T12:51:00.000Z"
    },
    "nickname": "Regular shopper",
    "avatarUrl": "https://lh3.example.com/a/buyer-avatar",
    "roleOverride": { "sys": { "id": "3trmXRLXeZN2RTHvVj3hFDN5546vbp", "type": "Refer", "targetType": "ServiceUserRole" } },
    "enableLogin": true
  }
}
```

```api-endpoint
{
  "title": "Partially update a ServiceUser (JSON Patch)",
  "method": "PATCH",
  "path": "/spaces/{spaceId}/service-users/{serviceUserId}",
  "description": "Updates only part of a ServiceUser with RFC 6902 JSON Patch. As in the example below, setting roleOverride applies that ServiceUserRole to this member alone. The request Content-Type header must be application/json-patch+json. Because the resource has no version, there is no X-Weegloo-Version header.",
  "responseStatus": 200,
  "baseUrl": "https://cma.weegloo.com/v1",
  "requestContentType": "application/json-patch+json",
  "pathParameterSchema": {
    "spaceId": { "type": "string", "description": "The sys.id of the Space", "required": true },
    "serviceUserId": { "type": "string", "description": "The sys.id of the ServiceUser", "required": true }
  },
  "requestHeaderSchema": {
    "Authorization": { "type": "string", "description": "Bearer token (CMA authentication)" },
    "Content-Type": { "type": "string", "description": "application/json-patch+json (RFC 6902 JSON Patch)" }
  },
  "requestBodySchema": {
    "type": "array",
    "description": "An array of RFC 6902 JSON Patch operations (op / path / value / from). path is an RFC 6901 JSON Pointer.",
    "items": {
      "type": "object",
      "required": ["op", "path"],
      "properties": {
        "op": { "type": "string", "enum": ["add", "remove", "replace", "move", "copy", "test"], "description": "Operation kind" },
        "path": { "type": "string", "description": "Target location (JSON Pointer). Example: /roleOverride" },
        "value": { "description": "The value used by add/replace/test" },
        "from": { "type": "string", "description": "The source location for move/copy" }
      }
    },
    "example": [
      { "op": "add", "path": "/roleOverride", "value": { "sys": { "id": "3trmXRLXeZN2RTHvVj3hFDN5546vbp", "type": "Refer", "targetType": "ServiceUserRole" } } }
    ]
  },
  "responseExample": {
    "sys": {
      "id": "3trmXRM3RqbgSnifyg7PSusr01Ex",
      "type": "ServiceUser",
      "space": { "sys": { "id": "tcq4V2Xb", "type": "Refer", "targetType": "Space" } },
      "provider": "google",
      "email": "buyer@example.com",
      "createdAt": "2026-06-18T12:50:00.000Z",
      "updatedAt": "2026-06-18T12:52:00.000Z"
    },
    "nickname": "Regular shopper",
    "avatarUrl": "https://lh3.example.com/a/buyer-avatar",
    "roleOverride": { "sys": { "id": "3trmXRLXeZN2RTHvVj3hFDN5546vbp", "type": "Refer", "targetType": "ServiceUserRole" } },
    "enableLogin": true
  }
}
```

## Related documents {#related-documents}

- [ServiceUserRole](/api/reference/cma/service-user-role.md): The permission bundle to give to `roleOverride`.
- [ServiceLogin](/api/reference/cma/service-login.md): Member sign-up and default-role (`defaultRole`) settings.
- [ACMA/ACDA overview](/api/reference/acma.md): The API a *ServiceUser* calls.
- [Reading the member directory in a Script](/api/reference/script/statements.md#service-user-reads): How to look a member up by id or email inside a *Script*, and the limits on it.
