# CRM · Templates

Part of AppEngine API Documentation. Full index: https://appengine.appmint.io/documentation.md
## POST /crm/send-template

**Send a templated message**

`operationId: CRMController_sendTemplate`

Renders a message template and sends it. This is the path for transactional mail that should look like every other message from the org — the template chain resolves org override, then shared-org, then the factory default.

Use `POST /crm/test-template` first to see the rendered output without sending.

#### Signature

```http
POST /crm/send-template (body) -> The sent message
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Sends on every call — there is no duplicate guard here, unlike `POST /crm/inbox/update`.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /crm/test-template`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

Which template, to whom, with what data.

```json
{
  "template": "order-confirmation",
  "to": "ada@example.com",
  "channel": "email",
  "data": {
    "orderNumber": "A7K2M9QX4"
  }
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The sent message |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /crm/test-template

**Test a message template**

`operationId: CRMController_testTemplate`

Renders a template with sample data and returns the result **without sending it**. The safe way to check wording and interpolation before mailing customers.

#### Signature

```http
POST /crm/test-template (body) -> The rendered template
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Nothing is sent and nothing is stored.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /crm/send-template`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

The template and the data to render it with.

```json
{
  "template": "order-confirmation",
  "data": {
    "orderNumber": "A7K2M9QX4"
  }
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The rendered template |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /crm/send-invitation

**Send an invitation**

`operationId: CRMController_sendInvitation`

Sends an invitation to join the organization. The invitee receives a link to accept.

#### Signature

```http
POST /crm/send-invitation (body) -> The invitation result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Sends every time — re-inviting an existing member mails them again.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Request body

Who to invite.

```json
{
  "email": "ada@example.com",
  "role": "User"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The invitation result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

