# Module definition

> Describe your CoSuite modules in the manifest (contract 1.7). Features, API with OpenAPI 3.1 and scopes, webhooks, provides, data categories and markets, plus the rules the conformance test enforces.

Source: https://cosuite.io/en/developers/module-definition

Since contract version **1.7**, each module in your [manifest](https://cosuite.io/en/developers/contract#manifest) can describe itself in detail. The CoSuite catalog, the sign-up flow, your app's page in CoSuite, the cosuite.io product pages and (in phase 2) the customer API reference are all generated from these fields. **Every field is optional**; a 1.6 manifest stays valid as it is.

## Example {#example}

```json
{
  "key": "dent.treatment",
  "name": { "tr": "Hasta ve tedavi planı", "en": "Patients and treatment plans", "az": "Xəstə və müalicə planı" },
  "description": { "tr": "Hasta kartı ve tedavi planı.", "en": "Patient records and treatment plans.", "az": "Xəstə kartı və müalicə planı." },
  "limits": [{ "key": "smsPerMonth", "unit": "count_per_month" }],
  "features": [
    { "key": "plan_pdf", "name": { "tr": "Tedavi planı PDF'i", "en": "Treatment plan PDF", "az": "Müalicə planı PDF" } },
    { "key": "sms", "name": { "tr": "SMS hatırlatma", "en": "SMS reminders", "az": "SMS xatırlatma" }, "limit": "smsPerMonth" }
  ],
  "api": { "version": "2026-11", "openapi": "/openapi.json", "scopes": [{ "key": "patients:read" }, { "key": "patients:write" }] },
  "webhooks": [{ "type": "treatment.completed", "scope": "patients:read", "schema": { "type": "object" } }],
  "provides": [],
  "dataCategories": ["identity", "contact", "health"],
  "markets": [
    { "country": "TR", "locales": ["tr"] },
    { "country": "AZ", "locales": ["az"], "price": { "currency": "AZN", "amount": 25 } }
  ]
}
```

## Fields {#fields}

| Field | Meaning |
|---|---|
| `key`, `name`, `limits`, `usage` | Unchanged from earlier versions (see the [contract](https://cosuite.io/en/developers/contract#manifest)). Module key `<appKey>.<module>`; `name` per language, up to 200 characters. |
| `description` | Per-language description, up to 1000 characters. |
| `features[]` | The module's capabilities: `key` (lowercase, `^[a-z][a-z0-9_]*$`), per-language `name`, optional per-language `description` and an optional `limit` it depends on (one of the same module's `limits[].key`). |
| `api` | The endpoints the module exposes to customers. `openapi`: an OpenAPI **3.1** document, either a URL (https, or a path relative to `baseUrl`; JSON only, at most 2 MB) or an embedded object. `scopes[]`: the module's scopes in `resource:action` form (`patients:read`), each with an optional per-language `name`. `version`: your API version. |
| `webhooks[]` | Events the module emits: `type` (dotted lowercase, for example `treatment.completed`), optional per-language `name` and `description`, an optional subscription `scope` (one of `api.scopes`) and a JSON Schema for `data`. |
| `provides[]` | Shared business functions the module takes over in CoSuite: `crm`, `quotes`, `einvoice`, `expenses`, `inventory`, `projects`, `inbox`, `booking`, `reviews`, `payments`, `reports`, `website`, `seo`, `social`, `shipping`, `hr`, `pos`. Two modules never provide the same function for the same business at the same time. |
| `dataCategories[]` | Personal data the module processes: `identity`, `contact`, `financial`, `health`, `location`, `biometric`, `children`, `communications`, `media`, `usage`, `employment`, `legal`. Used for privacy notices (GDPR, KVKK) and review. |
| `markets[]` | Countries where the module is offered (`country`, ISO 3166-1 alpha-2) and their languages (`locales`, taken from the manifest's `locales`); an optional country price `{ currency, amount }`. If empty, the market is decided in CoSuite. |

Limits at a glance: up to 64 features, 64 scopes, 64 webhooks, 16 `provides`, 32 data categories and 100 markets per module.

## Rules the conformance test enforces {#rules}

The [conformance test](https://cosuite.io/en/developers/sdk#conformance) checks only the fields you fill in. The partner portal runs the same checks when you submit.

- **Texts in every market language.** For every locale used in `markets`, the module's `name`, its `description` and every feature's `name` must be filled in.
- **Market locales come from the manifest.** Each locale in `markets[].locales` must also be in the manifest's `locales`.
- **No duplicate keys** in `features`, `api.scopes`, `webhooks` (by `type`) and `markets` (by `country`); no duplicates in `provides`.
- **Feature limits exist.** A feature's `limit` must be one of the module's `limits[].key`.
- **Webhook scopes exist.** A webhook's `scope` requires an `api` definition and must be one of `api.scopes`.
- **Known values only.** `provides` and `dataCategories` accept only the values listed above. CoSuite itself ignores unknown values (forward compatibility), but the test rejects them to catch typos.
- **OpenAPI is checked** for every module with an `api`: the document is downloaded (or read inline) and validated as described below.

## OpenAPI requirements {#openapi}

The test checks the parts CoSuite relies on; it is not a full schema validation.

- `openapi` is `3.1.x`; `info.title` and `info.version` are present; `paths` is not empty and every path starts with `/`.
- **Every operation requires at least one scope** through the `cosuite` security scheme: `security: [{ "cosuite": ["<scope>"] }]`. An operation without its own `security` inherits the root-level `security`.
- Every scope used in the document must be declared in the module's `api.scopes`.
- `operationId` values are unique.
- When `openapi` is a URL it must be https if your `baseUrl` is https, must return `200` with JSON (YAML is not supported) within 10 seconds, without redirects, and must be at most 2 MB.

A minimal valid document:

```json
{
  "openapi": "3.1.0",
  "info": { "title": "DentCloud treatment API", "version": "2026-11" },
  "security": [{ "cosuite": ["patients:read"] }],
  "components": {
    "securitySchemes": {
      "cosuite": { "type": "http", "scheme": "bearer", "bearerFormat": "CoSuite API key", "description": "CoSuite customer API key; the gateway checks the scopes in security" }
    }
  },
  "paths": {
    "/patients": {
      "get": { "operationId": "listPatients", "responses": { "200": { "description": "Patients" } } },
      "post": {
        "operationId": "createPatient",
        "security": [{ "cosuite": ["patients:write"] }],
        "responses": { "201": { "description": "Created" } }
      }
    }
  }
}
```

The `cosuite` scheme above is the final definition: customers send their CoSuite API key as a bearer token to the gateway, which checks the scopes listed in `security`. Optionally set `servers[0].url` to the base path of your API on the same origin as your app (for example `https://app.dentcloud.example/api`); the gateway forwards requests there.

## How customers reach your API {#gateway}

Customers call your module's endpoints through CoSuite's gateway at `api.cosuite.io` with their own CoSuite key. The request reaches your app with a Connect [signature](https://cosuite.io/en/developers/contract#signature) and an `X-CoSuite-Tenant` header that tells you which business is calling. See [Gateway & customer API](https://cosuite.io/en/developers/customer-api) for the headers, your obligations and the error codes.

## Markets and languages {#markets}

- A customer only sees modules that are offered in **their own country**. If you list `markets`, your module is shown only in those countries.
- Text is **required** in each market's languages (see [rules](#rules)). Other languages are optional.
- `price` sets a local price for that country. Without it, CoSuite converts the module's USD price at the current exchange rate.
- If `markets` is empty or missing, CoSuite decides where the module is offered.

## Keys are permanent {#permanent-keys}

Module, feature, limit, scope and webhook keys are part of the contract once your module is live. Do not rename them; add a new key and keep the old one for at least 6 months (see [versioning](https://cosuite.io/en/developers/contract#versioning)).
