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.
Since contract version 1.7, each module in your 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
{
"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
| Field | Meaning |
|---|---|
key, name, limits, usage |
Unchanged from earlier versions (see the contract). 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
The conformance test 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'sname, itsdescriptionand every feature'snamemust be filled in. - Market locales come from the manifest. Each locale in
markets[].localesmust also be in the manifest'slocales. - No duplicate keys in
features,api.scopes,webhooks(bytype) andmarkets(bycountry); no duplicates inprovides. - Feature limits exist. A feature's
limitmust be one of the module'slimits[].key. - Webhook scopes exist. A webhook's
scoperequires anapidefinition and must be one ofapi.scopes. - Known values only.
providesanddataCategoriesaccept 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
The test checks the parts CoSuite relies on; it is not a full schema validation.
openapiis3.1.x;info.titleandinfo.versionare present;pathsis not empty and every path starts with/.- Every operation requires at least one scope through the
cosuitesecurity scheme:security: [{ "cosuite": ["<scope>"] }]. An operation without its ownsecurityinherits the root-levelsecurity. - Every scope used in the document must be declared in the module's
api.scopes. operationIdvalues are unique.- When
openapiis a URL it must be https if yourbaseUrlis https, must return200with JSON (YAML is not supported) within 10 seconds, without redirects, and must be at most 2 MB.
A minimal valid document:
{
"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
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 and an X-CoSuite-Tenant header that tells you which business is calling. See Gateway & customer API for the headers, your obligations and the error codes.
Markets and languages
- 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). Other languages are optional.
pricesets a local price for that country. Without it, CoSuite converts the module's USD price at the current exchange rate.- If
marketsis empty or missing, CoSuite decides where the module is offered.
Keys are permanent
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).