# Compliance setup

A brokerage sets up its compliance work in the compliance hub in BrokerPlus. This page shows the
parts of that setup that the API reads and changes. The API does not make a requirement easier to
meet: anything that turns a check off, waives an item, or clears a finding stays in BrokerPlus,
with a named person behind it.

This API is in beta. Any endpoint can change in a breaking way without notice, so watch the
[changelog](/changelog).

## Who can change the setup

A key can do what its broker can do in the compliance hub, and nothing more. A broker changes the
templates of the teams they can change. Only a compliance administrator changes the setup of the
whole brokerage. A change that the broker cannot make gets `403`, with a message that says why.
A key with the `read_only` limit can read all of it. See [Authentication](/authentication).

## Package templates

A compliance package is one PDF that holds the documents of a deal for a lender or an auditor. A
package template sets the layout of the package: the cover page, and the documents in it, in
order. Each document is a slot. A team has its own templates. The brokerage can also set templates
for every team, and only a compliance administrator can change those.

`GET /v1/compliance/package-templates` lists the templates, the brokerage's first.
`GET /v1/compliance/package-requirements` lists the requirements that a slot can hold: put a `key`
in the slot's `requirement_key`.

```bash title="curl"
curl -X POST "https://api.mos.getbrokerplus.ca/v1/compliance/package-templates" \
  -H "Authorization: Bearer $BROKERPLUS_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "team_id": "cm...team",
    "name": "Purchase file",
    "slots": [
      { "requirement_key": "on_borrower_disclosure", "display_name": "Disclosure", "position": 0 },
      { "requirement_key": "custom-library:cm...", "display_name": "Brokerage checklist", "position": 1, "required": false }
    ]
  }'
```

```json
{
  "success": true,
  "data": {
    "object": "compliance_package_template",
    "id": "cm...",
    "owner": "team",
    "team_id": "cm...team",
    "team_name": "Purchase team",
    "name": "Purchase file",
    "include_cover": true,
    "cover_title": "Compliance package",
    "slots": [
      {
        "object": "compliance_package_template_slot",
        "requirement_key": "on_borrower_disclosure",
        "display_name": "Disclosure",
        "required": true,
        "included": true,
        "max_age_days": null,
        "position": 0
      }
    ]
  }
}
```

Send `team_id: null` to make a brokerage template. `PATCH /v1/compliance/package-templates/{id}`
changes the fields that you send, and `slots` replaces all the slots. The owner of a template cannot
change. `DELETE` archives the template, as the hub does. A package that is already on a deal keeps
the layout that it was made from.

A template sets a layout only. A required slot stops a package build while it has no document, but
a template does not change what a deal must have before it goes to a lender.

## A deal's package

A deal has one compliance package at most. `POST /v1/deals/{id}/compliance/package` with a
`template_id` makes it from one of the deal team's templates, or the brokerage's, and fills each
slot with the deal's documents for that requirement. A new package answers `201`. Send it again to
make the package again from a template: that answers `200`.

`GET /v1/deals/{id}/compliance/package` reads it: the cover, the items in order, and the
`findings` of the package's own checks. It answers `404` when the deal has no package.
`PATCH /v1/deals/{id}/compliance/package` changes the cover, and the name, position and
`included` of each item that you send by `id`.

`POST /v1/deals/{id}/compliance/package/build` merges the package into one PDF. It answers `202`,
and `status` is `building` until the PDF is ready. A finding with `severity: "blocker"` stops the
build with `409 PACKAGE_BLOCKED`, and `details.findings` lists them: a required document that is
missing or left out, or a package with nothing in it. A blocker is cleared in the deal, not here.
A change after a build sets `stale: true` until you build again.

`GET /v1/deals/{id}/compliance/package/download` answers a link to the PDF that works for five
minutes. It answers `409` while the package is not built, or is stale.

## The compliance program

`GET /v1/compliance/program` reads the brokerage's compliance program: the compliance officers, how
often a client is screened again, the ways a client proves their identity, who gets an email for
each alert, and whether each of the five program documents is there.

Through the API, a compliance administrator changes only the facts about the brokerage that the
borrower disclosure prints:

```bash title="curl"
curl -X PATCH "https://api.mos.getbrokerplus.ca/v1/compliance/program" \
  -H "Authorization: Bearer $BROKERPLUS_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "representation_basis": "borrower_only", "lenders_acted_for_previous_year": 12, "was_lender_previous_year": false }'
```

Send `null` to clear a fact: the disclosure then prints it unanswered. Any other field of the program
gets `400`. A change to how often clients are screened, how a client proves their identity, or who
hears an alert can make a check easier to pass, so it is made in BrokerPlus.

These read the rest of the setup. None of them change it.

| Endpoint | What it returns |
| --- | --- |
| `GET /v1/compliance/trainings` | The compliance training that each broker finished. Only a brokerage administrator can read it. |
| `GET /v1/compliance/retention-policies` | How many years each kind of record is kept, by province. |
| `GET /v1/compliance/verifier-policy` | Whether the instant document check is on, who can run it, and how strict it is. |
| `GET /v1/compliance/monitoring-alerts` | The alerts that screening raised about clients. A broker sees the alerts on their own clients. |

An alert is dismissed or resolved in BrokerPlus, by a person who reviewed it.

## E-signing rules

A team that connected an e-signing provider in BrokerPlus, such as DocuSign or BoldSign, sends its
documents through it. `GET /v1/signing-policies` lists the rules of your teams: the `default`
provider, and a `lender` exception for a lender that does not accept it.

```bash title="curl"
curl -X POST "https://api.mos.getbrokerplus.ca/v1/signing-policies" \
  -H "Authorization: Bearer $BROKERPLUS_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ "scope": "lender", "lender_slug": "scotiabank", "provider": "boldsign", "note": "Scotia asks for BoldSign" }'
```

A rule names the provider, and the rule goes on the team that connected it. When more than one of
your teams connected the provider, send `team_id`. A team has one default and one rule per lender,
so sending the same rule again changes it. `DELETE /v1/signing-policies/{id}` removes a rule. A
provider is connected in BrokerPlus, never through the API.

## In an AI assistant

The [MCP server](/mcp) has a tool for every operation on this page, the download link and the
monitoring alerts included. An assistant can repeat what it reads to anyone it talks to, so treat a
key you give an assistant the way you treat the client's file. Archiving a template and deleting an
e-signing rule are marked destructive, so the assistant asks you first.
