Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,44 @@ user key: `create_ai_service_user`, `list_ai_service_users`,
Full tables and an MCP example: [docs/hub/account.md](./docs/hub/account.md),
[docs/api/public.md](./docs/api/public.md).

## Campaigns and triggers: the provider integration id

The server now **requires the provider integration id** when you create an
Email, Push or SMS campaign, and on every trigger action. Pick it from
`get_email_integrations` / `get_push_integrations` / `get_sms_integrations`.
Email and Push put it inside `campaign`; SMS sends it at the top level, next to
(and different from) `databaseIntegrationId`:

```python
norbix.hub.notifications.create_email_campaign(
campaign={"templateId": "tpl_123", "integrationId": "int_email", "source": "allUsers"}
)
norbix.hub.notifications.create_push_campaign(
campaign={"source": "allUsers", "templateId": "tpl_456", "integrationId": "int_push"}
)
norbix.hub.notifications.create_sms_campaign(
templateId="tpl_789",
integrationId="int_sms",
deliveryType="PhoneNumbers",
phoneNumbers={"recipientsSourceType": "PhoneNumbers", "phoneNumbers": ["+37060000000"]},
)
```

A trigger action (`save_schema_trigger`, `save_files_trigger`,
`save_membership_trigger`, `save_payments_trigger`) takes the same required
`integrationId`, plus the optional `language` (template language) and
`initiatorId` (who the send is attributed to) on Email, Push and SMS actions.
Two related calls:

- `norbix.hub.triggers.get_triggers_needing_attention(triggerType="Schema")` —
triggers that need a fix (for example, their provider is gone); `{"items": [...]}`.
- `norbix.hub.account.check_project_languages(project_id, languages=["en", "de"])` —
a dry run before `update_project_languages`: which templates miss a language;
`{"templates": [...]}`. Account scope.

Details: [docs/hub/triggers.md](./docs/hub/triggers.md),
[docs/hub/sms.md](./docs/hub/sms.md), [docs/hub/push.md](./docs/hub/push.md).

## Errors

```python
Expand Down Expand Up @@ -365,6 +403,10 @@ uv run python scripts/generate_endpoints.py

This refreshes `src/norbix_python/api/`, `hub/`, matching tests under `tests/api` and `tests/hub`, and docs under `docs/`.

Some methods are **hand-written** and marked `HAND-WRITTEN` in the source
(`hub/triggers.py`, its registration in `hub/__init__.py`, and
`account.check_project_languages`). Keep them when you regenerate.

## Development

```bash
Expand Down
3 changes: 2 additions & 1 deletion docs/hub/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

| Module | Endpoints |
| --- | ---: |
| [`account`](./account.md) | 58 |
| [`account`](./account.md) | 59 |
| [`ai`](./ai.md) | 14 |
| [`database`](./database.md) | 41 |
| [`echo`](./echo.md) | 1 |
Expand All @@ -14,4 +14,5 @@
| [`notifications`](./notifications.md) | 117 |
| [`payments`](./payments.md) | 16 |
| [`scheduler`](./scheduler.md) | 8 |
| [`triggers`](./triggers.md) | 1 |
| [`webhooks`](./webhooks.md) | 8 |
1 change: 1 addition & 0 deletions docs/hub/account.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Access with `norbix.hub.account`.
| `update_project_description` | `PATCH` | `/{version}/account/projects/{projectId}/settings/description` | `account` |
| `disable_project` | `PATCH` | `/{version}/account/projects/{projectId}/disable` | `account` |
| `enable_project` | `PATCH` | `/{version}/account/projects/{projectId}/enable` | `account` |
| `check_project_languages` | `POST` | `/{version}/account/projects/{projectId}/settings/languages/check` | `account` |
| `update_project_languages` | `PATCH` | `/{version}/account/projects/{projectId}/settings/languages` | `account` |
| `update_project_url` | `PATCH` | `/{version}/account/projects/{projectId}/settings/url` | `account` |
| `update_project_name` | `PATCH` | `/{version}/account/projects/{projectId}/settings/name` | `account` |
Expand Down
6 changes: 4 additions & 2 deletions docs/hub/push.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ field plus the audience's own fields:
| rows of a database collection | `collection` | `schemaName`, `fields` (the record fields that hold the recipient), `fieldType` (`User` or `Email`), optional `roleNames`, `languages` |
| raw device tokens | `devices` | `devices`: a list of `{ token, deliveryFamily }`, `deliveryFamily` one of `Ios`, `Android`, `Chrome`, `Safari`, `Expo` |

Every target also takes `templateId` (required) and the optional `integrationId`,
`language`, `notes`, `campaignTime` (Unix seconds) and `mappedTokens`. Note the
Every target also takes `templateId` and `integrationId` (both required —
`integrationId` is the push provider, from `get_push_integrations`), and the
optional `language`, `notes`, `campaignTime` (Unix seconds) and `mappedTokens`. Note the
spelling: `rolesNames` on `allUsers`, but `roleNames` on `collection` — the
gateway names them differently.

Expand All @@ -31,6 +32,7 @@ client.hub.notifications.create_push_campaign(
campaign={
"source": "allUsers",
"templateId": "tpl_123",
"integrationId": "int_push",
"userTags": ["beta"],
}
)
Expand Down
6 changes: 5 additions & 1 deletion docs/hub/sms.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,17 @@ and the settings object repeats the audience name in `recipientsSourceType`:
Every settings object also takes `campaignTime` (Unix seconds, UTC — set a
future time so the campaign can be reviewed in the dashboard first), and the
optional `mappedTokens` and `respectTimeZoneSettings`. The request itself takes
`templateId` (required), and the optional `language` and `databaseIntegrationId`.
`templateId` and `integrationId` (both required — `integrationId` is the SMS
provider, from `get_sms_integrations`), and the optional `language` and
`databaseIntegrationId` (the database behind a `Collection` audience — a
different id from `integrationId`).
Note the spelling: `rolesNames` on `allUsers`, but `roleNames` on `collection` —
the gateway names them differently.

```python
client.hub.notifications.create_sms_campaign(
templateId="tpl_123",
integrationId="int_sms",
deliveryType="PhoneNumbers",
phoneNumbers={
"recipientsSourceType": "PhoneNumbers",
Expand Down
43 changes: 43 additions & 0 deletions docs/hub/triggers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# HUB · Triggers

Access with `norbix.hub.triggers`. This module is hand-written (not generated).

| Method | Verb | Path | Scope |
| --- | --- | --- | --- |
| `get_triggers_needing_attention` | `GET` | `/{version}/triggers/attention` | `project` |

Pass `triggerType` — one of `Membership`, `Schema`, `Files`, `Payments`, `Ai`.
The answer is `{"items": [{"triggerId", "triggerType", "reason", "atUtc"}, ...]}`:
the triggers of that type that need a fix, for example because their provider
integration was deleted.

```python
norbix.hub.triggers.get_triggers_needing_attention(triggerType="Schema")
```

## The trigger action

Each module saves its own triggers (`database.save_schema_trigger`,
`files.save_files_trigger`, `membership.save_membership_trigger`,
`payments.save_payments_trigger`). They all send `trigger.action`, and the
server requires `integrationId` on it — the provider that does the work. Email,
Push and SMS actions also take the optional `language` (which template language
to send) and `initiatorId` (who the send is attributed to):

```python
norbix.hub.database.save_schema_trigger(
trigger={
"name": "welcome",
"isEnabled": True,
"action": {
"type": "Email",
"integrationId": "int_email",
"templateId": "tpl_123",
"language": "de",
"initiatorId": "user_1",
},
}
)
```

Everything here is asserted in `tests/hub/test_triggers.py`.
Loading
Loading