---
title: "For a firm: Connect the firm's practice system, step 1: the credentials (billing, admin)"
method: PUT
path: "/v1/admin/tenants/{tenant}/connector"
tags: ["admin"]
---

# For a firm: Connect the firm's practice system, step 1: the credentials (billing, admin)

`PUT /v1/admin/tenants/{tenant}/connector`

## Request

- Base URL: `https://api.sixminute.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.sixminute.ai/v1/admin/tenants/{tenant}/connector`
- Auth: HTTP bearer

The credentials are VERIFIED before anything is stored: the adapter connects and probes, and a failure is a 422 whose one error's path names the step that failed (`step.tls`, `step.login`, `step.schema`, `step.rights`) so an administrator is sent to the one screen in their own system where the answer is. On success the row is sealed under the firm's key, a NEW connector is stored as `pending_mapping`, the system's employees are written to the team table, and the answer carries the team proposal, matched to the firm's members by exact email and by nothing else (D-166). The adapter's declared pick-list fields are bound in the same step: one attribute per field, `source: connector`, keyed `<kind>_<field>` or by the standard it names, created or rebound to the row a former connection of the same system left behind, and a firm-wide field's one set with it (D-174). A connector of ANOTHER kind is a 409 naming Disconnect; the same kind again re-verifies, re-seals, keeps the team and its bindings and keeps a firm that was `connected` or `needs_reconnect` connected, because a firm that has already confirmed its team is not sent through that step again by a reconnection. The deliveries a former connection left keep the kind they were sent to, as history. For a kind each member signs in to with their own account (`capabilities.identity` is `sign_in`) the caller must be an ADMINISTRATOR (403 for billing) and the credentials are their OWN account (a username and password, or an `api_token` they made in the system): the firm's row seals which installation it is and no session, the connector is `connected` at once, the administrator's own session is stored as `PUT /v1/connector/account` stores a member's, and `team` is null. It answers as soon as the system accepted the sign-in and runs NO sync: the summary's counts are what the firm held before, and the client sends `POST /v1/connector/sync` itself, straight after, reading `GET /v1/connector/sync/progress` while it runs. The same installation again is that administrator signing in again; another installation while connected is a 409 naming Disconnect. An account of the system that another member already signed in with is a 409. An operator is refused such a connect with a 422: it takes a person's own password. A credential whose host resolves to a loopback, private, link-local or unspecified address is a 422 on the path `host`, before anything is dialled. The system's narrative ceiling is not copied into the firm's settings: the limit in force is the firm's own length under the ceiling, computed on every read.

Operator mount: an operator acting for the firm named in the path, as its oldest active admin, else its oldest active billing member; `X-Six-Minute-Acting-As` names them. 404 for no such firm, 409 `urn:six-minute:problem:no-acting-member` for one with neither.

## Path parameters

- `tenant` string, required

## Request body

- union
  - object
    - `kind` 'urios', required
    - `host` string, required
    - `port` integer
    - `database` string, required
    - `user` string, required
    - `password` string, required
  - object
    - `kind` 'legalsense', required
    - `host` string, required
    - `username` string
    - `password` string
    - `totp` string
    - `api_token` string
  - object
    - `kind` 'fake', required
    - `seed` string

## Response `200`

The connector, and the team table to confirm.

- object
  - `connector` object, required
    - `kind` 'urios' | 'legalsense' | 'fake', required
    - `status` 'pending_mapping' | 'connected' | 'needs_reconnect' | 'disabled', required
    - `capabilities` object, required
      - `accepts_by` 'billing' | 'approval', required
      - `identity` 'mapping' | 'sign_in', required
      - `change_feed` 'modified_since' | 'full_list', required
      - `narrative_max_chars` integer, nullable, required
      - `note_max_chars` integer, nullable
      - `insolvency_groups` false, required
      - `matter_visibility` 'firm' | 'member'
      - `reviewer` 'self' | 'configurable'
      - `fields` object[], required
        - `key` string, required
        - `label` string, required
        - `scope` 'firm' | 'matter', required
        - `required` boolean, required
        - `standard` 'utbms_task' | 'utbms_activity', nullable, required
    - `settings` object, nullable
      - `notation` string, nullable
      - `reviewer` union
        - object
          - `mode` 'timekeeper', required
        - object
          - `mode` 'person', required
          - `external_ref` string, required
          - `name` string, required
        - unknown
      - `auto_approve` string[]
    - `counts` object, required
      - `matters` integer, required
      - `clients` integer, required
      - `timekeepers` integer, required
      - `options` integer, required
    - `team_bound` integer, required
    - `team_unbound` integer, required
    - `last_sync_at` string, date-time, nullable
    - `last_error` string, nullable
  - `team` object, nullable, required
    - `rows` object[], required
      - `external_ref` string, required
      - `name` string, required
      - `email` string, nullable
      - `code` string, nullable
      - `active` boolean
      - `member_id` string, nullable
      - `bound_by` 'email' | 'admin' | 'sign_in', nullable
      - `bound_at` string, date-time, nullable
      - `note` string, nullable
      - `member_name` string, nullable
      - `member_email` string, nullable
    - `unmatched_members` object[], required
      - `member_id` string, required
      - `name` string
      - `email` string, required

## Other responses

- `400`: The body, query or path did not validate; `errors` lists the fields.
- `401`: No bearer token, or one that does not verify or has expired.
- `403`: The token verified but may not do this: no organisation, not provisioned, wrong role, or a device problem.
- `404`: No such row for this tenant.
- `409`: The id or the email already belongs to something else.
- `422`: The request is well-formed but cannot be carried out as it stands.
- `503`: A capability this service was not configured with, or a practice system that could not be reached; the `type` says which.

---

[API](https://skmtc.dev/sixminute/apis/sixminute-api.md) - [All operations](https://skmtc.dev/sixminute/apis/sixminute-api/llms.txt) - [OpenAPI document](https://skmtc.dev/sixminute/apis/sixminute-api/revisions/605577eadc10?raw)
