n8n-nodes-getcourse 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +38 -0
- package/README.md +359 -0
- package/dist/credentials/GetCourseApi.credentials.d.ts +10 -0
- package/dist/credentials/GetCourseApi.credentials.js +58 -0
- package/dist/credentials/GetCourseApi.credentials.js.map +1 -0
- package/dist/credentials/GetCourseTechApi.credentials.d.ts +11 -0
- package/dist/credentials/GetCourseTechApi.credentials.js +63 -0
- package/dist/credentials/GetCourseTechApi.credentials.js.map +1 -0
- package/dist/credentials/accountAddress.d.ts +11 -0
- package/dist/credentials/accountAddress.js +116 -0
- package/dist/credentials/accountAddress.js.map +1 -0
- package/dist/icons/getcourse.dark.svg +15 -0
- package/dist/icons/getcourse.svg +11 -0
- package/dist/nodes/GetCourse/GetCourse.node.d.ts +9 -0
- package/dist/nodes/GetCourse/GetCourse.node.js +48 -0
- package/dist/nodes/GetCourse/GetCourse.node.js.map +1 -0
- package/dist/nodes/GetCourse/GetCourse.node.json +40 -0
- package/dist/nodes/GetCourse/v1/actions/call/index.d.ts +3 -0
- package/dist/nodes/GetCourse/v1/actions/call/index.js +98 -0
- package/dist/nodes/GetCourse/v1/actions/call/index.js.map +1 -0
- package/dist/nodes/GetCourse/v1/actions/deal/description.d.ts +2 -0
- package/dist/nodes/GetCourse/v1/actions/deal/description.js +261 -0
- package/dist/nodes/GetCourse/v1/actions/deal/description.js.map +1 -0
- package/dist/nodes/GetCourse/v1/actions/deal/execute.d.ts +2 -0
- package/dist/nodes/GetCourse/v1/actions/deal/execute.js +181 -0
- package/dist/nodes/GetCourse/v1/actions/deal/execute.js.map +1 -0
- package/dist/nodes/GetCourse/v1/actions/deal/index.d.ts +2 -0
- package/dist/nodes/GetCourse/v1/actions/deal/index.js +8 -0
- package/dist/nodes/GetCourse/v1/actions/deal/index.js.map +1 -0
- package/dist/nodes/GetCourse/v1/actions/dialog/index.d.ts +3 -0
- package/dist/nodes/GetCourse/v1/actions/dialog/index.js +262 -0
- package/dist/nodes/GetCourse/v1/actions/dialog/index.js.map +1 -0
- package/dist/nodes/GetCourse/v1/actions/helpdesk/index.d.ts +3 -0
- package/dist/nodes/GetCourse/v1/actions/helpdesk/index.js +305 -0
- package/dist/nodes/GetCourse/v1/actions/helpdesk/index.js.map +1 -0
- package/dist/nodes/GetCourse/v1/actions/index.d.ts +5 -0
- package/dist/nodes/GetCourse/v1/actions/index.js +119 -0
- package/dist/nodes/GetCourse/v1/actions/index.js.map +1 -0
- package/dist/nodes/GetCourse/v1/actions/lesson/index.d.ts +3 -0
- package/dist/nodes/GetCourse/v1/actions/lesson/index.js +180 -0
- package/dist/nodes/GetCourse/v1/actions/lesson/index.js.map +1 -0
- package/dist/nodes/GetCourse/v1/actions/offer/index.d.ts +3 -0
- package/dist/nodes/GetCourse/v1/actions/offer/index.js +98 -0
- package/dist/nodes/GetCourse/v1/actions/offer/index.js.map +1 -0
- package/dist/nodes/GetCourse/v1/actions/school/index.d.ts +3 -0
- package/dist/nodes/GetCourse/v1/actions/school/index.js +139 -0
- package/dist/nodes/GetCourse/v1/actions/school/index.js.map +1 -0
- package/dist/nodes/GetCourse/v1/actions/user/description.d.ts +2 -0
- package/dist/nodes/GetCourse/v1/actions/user/description.js +499 -0
- package/dist/nodes/GetCourse/v1/actions/user/description.js.map +1 -0
- package/dist/nodes/GetCourse/v1/actions/user/execute.d.ts +2 -0
- package/dist/nodes/GetCourse/v1/actions/user/execute.js +270 -0
- package/dist/nodes/GetCourse/v1/actions/user/execute.js.map +1 -0
- package/dist/nodes/GetCourse/v1/actions/user/index.d.ts +2 -0
- package/dist/nodes/GetCourse/v1/actions/user/index.js +8 -0
- package/dist/nodes/GetCourse/v1/actions/user/index.js.map +1 -0
- package/dist/nodes/GetCourse/v1/actions/webhook/index.d.ts +4 -0
- package/dist/nodes/GetCourse/v1/actions/webhook/index.js +179 -0
- package/dist/nodes/GetCourse/v1/actions/webhook/index.js.map +1 -0
- package/dist/nodes/GetCourse/v1/actions/webinar/index.d.ts +3 -0
- package/dist/nodes/GetCourse/v1/actions/webinar/index.js +376 -0
- package/dist/nodes/GetCourse/v1/actions/webinar/index.js.map +1 -0
- package/dist/nodes/GetCourse/v1/descriptions/common.d.ts +7 -0
- package/dist/nodes/GetCourse/v1/descriptions/common.js +142 -0
- package/dist/nodes/GetCourse/v1/descriptions/common.js.map +1 -0
- package/dist/nodes/GetCourse/v1/helpers/errors.d.ts +11 -0
- package/dist/nodes/GetCourse/v1/helpers/errors.js +90 -0
- package/dist/nodes/GetCourse/v1/helpers/errors.js.map +1 -0
- package/dist/nodes/GetCourse/v1/helpers/request.d.ts +7 -0
- package/dist/nodes/GetCourse/v1/helpers/request.js +79 -0
- package/dist/nodes/GetCourse/v1/helpers/request.js.map +1 -0
- package/dist/nodes/GetCourse/v1/methods/index.d.ts +2 -0
- package/dist/nodes/GetCourse/v1/methods/index.js +39 -0
- package/dist/nodes/GetCourse/v1/methods/index.js.map +1 -0
- package/dist/nodes/GetCourse/v1/methods/loadOptions.d.ts +7 -0
- package/dist/nodes/GetCourse/v1/methods/loadOptions.js +76 -0
- package/dist/nodes/GetCourse/v1/methods/loadOptions.js.map +1 -0
- package/dist/nodes/GetCourse/v1/transport/index.d.ts +18 -0
- package/dist/nodes/GetCourse/v1/transport/index.js +165 -0
- package/dist/nodes/GetCourse/v1/transport/index.js.map +1 -0
- package/dist/nodes/GetCourseLegacy/GetCourseLegacy.node.d.ts +9 -0
- package/dist/nodes/GetCourseLegacy/GetCourseLegacy.node.js +48 -0
- package/dist/nodes/GetCourseLegacy/GetCourseLegacy.node.js.map +1 -0
- package/dist/nodes/GetCourseLegacy/GetCourseLegacy.node.json +35 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/deal/description.d.ts +2 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/deal/description.js +287 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/deal/description.js.map +1 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/deal/execute.d.ts +2 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/deal/execute.js +150 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/deal/execute.js.map +1 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/deal/index.d.ts +2 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/deal/index.js +8 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/deal/index.js.map +1 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/export/description.d.ts +2 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/export/description.js +487 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/export/description.js.map +1 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/export/execute.d.ts +2 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/export/execute.js +252 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/export/execute.js.map +1 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/export/index.d.ts +2 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/export/index.js +8 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/export/index.js.map +1 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/field/index.d.ts +3 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/field/index.js +61 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/field/index.js.map +1 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/group/index.d.ts +3 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/group/index.js +42 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/group/index.js.map +1 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/index.d.ts +5 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/index.js +84 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/index.js.map +1 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/user/description.d.ts +2 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/user/description.js +87 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/user/description.js.map +1 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/user/execute.d.ts +5 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/user/execute.js +129 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/user/execute.js.map +1 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/user/index.d.ts +2 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/user/index.js +8 -0
- package/dist/nodes/GetCourseLegacy/v1/actions/user/index.js.map +1 -0
- package/dist/nodes/GetCourseLegacy/v1/descriptions/common.d.ts +14 -0
- package/dist/nodes/GetCourseLegacy/v1/descriptions/common.js +198 -0
- package/dist/nodes/GetCourseLegacy/v1/descriptions/common.js.map +1 -0
- package/dist/nodes/GetCourseLegacy/v1/descriptions/constants.d.ts +7 -0
- package/dist/nodes/GetCourseLegacy/v1/descriptions/constants.js +116 -0
- package/dist/nodes/GetCourseLegacy/v1/descriptions/constants.js.map +1 -0
- package/dist/nodes/GetCourseLegacy/v1/helpers/errors.d.ts +18 -0
- package/dist/nodes/GetCourseLegacy/v1/helpers/errors.js +141 -0
- package/dist/nodes/GetCourseLegacy/v1/helpers/errors.js.map +1 -0
- package/dist/nodes/GetCourseLegacy/v1/helpers/exportRows.d.ts +8 -0
- package/dist/nodes/GetCourseLegacy/v1/helpers/exportRows.js +100 -0
- package/dist/nodes/GetCourseLegacy/v1/helpers/exportRows.js.map +1 -0
- package/dist/nodes/GetCourseLegacy/v1/methods/index.d.ts +2 -0
- package/dist/nodes/GetCourseLegacy/v1/methods/index.js +39 -0
- package/dist/nodes/GetCourseLegacy/v1/methods/index.js.map +1 -0
- package/dist/nodes/GetCourseLegacy/v1/methods/loadOptions.d.ts +5 -0
- package/dist/nodes/GetCourseLegacy/v1/methods/loadOptions.js +92 -0
- package/dist/nodes/GetCourseLegacy/v1/methods/loadOptions.js.map +1 -0
- package/dist/nodes/GetCourseLegacy/v1/transport/index.d.ts +13 -0
- package/dist/nodes/GetCourseLegacy/v1/transport/index.js +204 -0
- package/dist/nodes/GetCourseLegacy/v1/transport/index.js.map +1 -0
- package/dist/nodes/GetCourseTrigger/GetCourseTrigger.node.d.ts +12 -0
- package/dist/nodes/GetCourseTrigger/GetCourseTrigger.node.js +339 -0
- package/dist/nodes/GetCourseTrigger/GetCourseTrigger.node.js.map +1 -0
- package/dist/nodes/GetCourseTrigger/GetCourseTrigger.node.json +32 -0
- package/dist/nodes/GetCourseTrigger/payload.d.ts +14 -0
- package/dist/nodes/GetCourseTrigger/payload.js +66 -0
- package/dist/nodes/GetCourseTrigger/payload.js.map +1 -0
- package/dist/utils/cache.d.ts +2 -0
- package/dist/utils/cache.js +27 -0
- package/dist/utils/cache.js.map +1 -0
- package/dist/utils/dates.d.ts +3 -0
- package/dist/utils/dates.js +70 -0
- package/dist/utils/dates.js.map +1 -0
- package/dist/utils/events.d.ts +14 -0
- package/dist/utils/events.js +92 -0
- package/dist/utils/events.js.map +1 -0
- package/dist/utils/httpError.d.ts +4 -0
- package/dist/utils/httpError.js +46 -0
- package/dist/utils/httpError.js.map +1 -0
- package/dist/utils/query.d.ts +4 -0
- package/dist/utils/query.js +42 -0
- package/dist/utils/query.js.map +1 -0
- package/dist/utils/rateLimiter.d.ts +3 -0
- package/dist/utils/rateLimiter.js +44 -0
- package/dist/utils/rateLimiter.js.map +1 -0
- package/dist/utils/router.d.ts +8 -0
- package/dist/utils/router.js +40 -0
- package/dist/utils/router.js.map +1 -0
- package/index.js +0 -0
- package/package.json +68 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 zenland-dev
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
7
|
+
the Software without restriction, including without limitation the rights to
|
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
9
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
|
10
|
+
so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Trademarks
|
|
26
|
+
|
|
27
|
+
The MIT grant above covers this package's own code and documentation. It does
|
|
28
|
+
not, and cannot, grant any right in third-party trademarks.
|
|
29
|
+
|
|
30
|
+
"GetCourse" and the GetCourse logo are trademarks of their owner. The mark is
|
|
31
|
+
reproduced in `icons/getcourse.svg` and `icons/getcourse.dark.svg` solely to
|
|
32
|
+
identify which service these nodes connect to — nominative use — and its
|
|
33
|
+
inclusion is not a claim of ownership, nor an endorsement, sponsorship or
|
|
34
|
+
affiliation. This package is an independent integration and is not produced,
|
|
35
|
+
endorsed or supported by GetCourse.
|
|
36
|
+
|
|
37
|
+
Nothing in the MIT licence sublicenses that mark. Anyone redistributing or
|
|
38
|
+
modifying this package remains subject to the trademark owner's own terms.
|
package/README.md
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# n8n-nodes-getcourse
|
|
2
|
+
|
|
3
|
+
n8n community nodes for [GetCourse](https://getcourse.ru) — the Russian online-school
|
|
4
|
+
platform — covering **both** of its APIs plus a webhook trigger.
|
|
5
|
+
|
|
6
|
+
GetCourse has two APIs that do not overlap and neither replaces the other:
|
|
7
|
+
|
|
8
|
+
| | **GetCourse** | **GetCourse Legacy** |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| API | Tech API, `/pl/api/v1/…` | Import/Export API |
|
|
11
|
+
| Docs | [redoc](https://getcourse.ru/pl/postback/redoc) | [help/api](https://getcourse.ru/help/api) |
|
|
12
|
+
| Keys | developer key **+** school key | the account's secret key |
|
|
13
|
+
| Creates | nothing | users, orders, payments |
|
|
14
|
+
| Bulk reads | offers, webinars, dictionaries — but never users or orders | users, orders, payments, group members |
|
|
15
|
+
| Single reads | users, orders, offers, dialogs, lessons, webinars | nothing |
|
|
16
|
+
|
|
17
|
+
So a real integration usually needs both: the Legacy node to create a user or export a
|
|
18
|
+
month of orders, the GetCourse node to read one order or move it to another status, and the
|
|
19
|
+
Trigger node to hear about it when something happens.
|
|
20
|
+
|
|
21
|
+
- [Installation](#installation)
|
|
22
|
+
- [Credentials](#credentials)
|
|
23
|
+
- [GetCourse node](#getcourse-node)
|
|
24
|
+
- [GetCourse Legacy node](#getcourse-legacy-node)
|
|
25
|
+
- [GetCourse Trigger](#getcourse-trigger)
|
|
26
|
+
- [Exporting data](#exporting-data)
|
|
27
|
+
- [Limits](#limits)
|
|
28
|
+
- [Data quirks worth knowing](#data-quirks-worth-knowing)
|
|
29
|
+
- [Feedback and bugs](#feedback-and-bugs)
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
In n8n: **Settings → Community nodes → Install**, then enter
|
|
34
|
+
`n8n-nodes-getcourse`.
|
|
35
|
+
|
|
36
|
+
Self-hosted, from the command line:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install n8n-nodes-getcourse
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Requires n8n 2.x and Node 20.19 or newer.
|
|
43
|
+
|
|
44
|
+
## Credentials
|
|
45
|
+
|
|
46
|
+
Both credentials address the account the same way. Pick **GetCourse Subdomain** and enter
|
|
47
|
+
the part in front of the domain — `myschool` for `myschool.getcourse.ru` — or, if your
|
|
48
|
+
account force-redirects that address to a domain of its own, pick **Custom Domain** and
|
|
49
|
+
enter that domain. The API answers only on the domain the account actually serves, and a
|
|
50
|
+
redirect is not followed: it would strip a POST body and hand the key to the other host.
|
|
51
|
+
|
|
52
|
+
### GetCourse Account API — for the Legacy node
|
|
53
|
+
|
|
54
|
+
One field: the account's **secret key**, from Профиль → Настройки аккаунта → АПИ. Generate
|
|
55
|
+
one with write access if you intend to import; a read-only key is enough for exports and
|
|
56
|
+
for the custom-field dictionary.
|
|
57
|
+
|
|
58
|
+
An import the account is not entitled to make does not say so. It comes back as HTTP 200 with
|
|
59
|
+
an empty body and creates nothing — no error code, no message. If you see «GetCourse answered
|
|
60
|
+
nothing at all», check the account's plan first and the key's write permission second: a key
|
|
61
|
+
that genuinely holds write access still fails this way on a plan without the Import API.
|
|
62
|
+
|
|
63
|
+
**Export Requests per Hour** (default 45) is a throttle this node applies on your behalf.
|
|
64
|
+
GetCourse allows an account 100 Export API requests per **two hours** in total, counting
|
|
65
|
+
every status check, and going over answers 903 for every other integration on that account
|
|
66
|
+
until the window clears. The default leaves room for a second workflow; lower it if the
|
|
67
|
+
account has other integrations, raise it if this n8n is the only caller.
|
|
68
|
+
|
|
69
|
+
The Import/Export API is available on paid plans only, and a plan that does not include it
|
|
70
|
+
does **not** announce itself with `error_code 917` the way the help page suggests. On a free
|
|
71
|
+
account with a write-enabled key, exports, the group list and the field dictionary all work
|
|
72
|
+
normally, while every import answers HTTP 200 with an empty body and writes nothing — no
|
|
73
|
+
code, no message. The node reports that as «GetCourse answered nothing at all» rather than
|
|
74
|
+
guessing. The Tech API is unaffected: the same account accepted Tech API writes with the
|
|
75
|
+
same key.
|
|
76
|
+
|
|
77
|
+
### GetCourse Tech API — for the GetCourse node and the Trigger
|
|
78
|
+
|
|
79
|
+
Two fields, because GetCourse issues the two halves to different people:
|
|
80
|
+
|
|
81
|
+
- **Developer Key** — issued to the integrator after
|
|
82
|
+
[this form](https://getcourse.ru/issuedeveloperkey). The same key for every school you
|
|
83
|
+
integrate.
|
|
84
|
+
- **School API Key** — handed out by the school itself, one per account. Not the same thing
|
|
85
|
+
as the account Secret Key above.
|
|
86
|
+
|
|
87
|
+
The node joins them with an underscore and sends `Authorization: Bearer <developer>_<school>`,
|
|
88
|
+
which is the documented format. A 403 means one half is wrong, they belong to different
|
|
89
|
+
schools, or the school has not enabled access for that developer key.
|
|
90
|
+
|
|
91
|
+
## GetCourse node
|
|
92
|
+
|
|
93
|
+
The Tech API. Reads and updates existing objects; it creates nothing, and it cannot list
|
|
94
|
+
users or orders at all.
|
|
95
|
+
|
|
96
|
+
| Resource | Operations |
|
|
97
|
+
|---|---|
|
|
98
|
+
| **User** (25) | Get · Get by Chat ID · Get by Telegram Chat ID · Get Custom Fields · Get Deals · Get Purchases · Get Trainings · Get Schedule · Get Goals · Get Diplomas · Get Groups · Get Balance · Get Lesson Answers · Get Survey Answers · Get Dialogs · Get HelpDesk Dialogs · Update · Update Custom Fields · Add to Groups · Remove From Groups · Set Groups · Add Balance · Set Personal Manager · Create Diploma · Add Comment |
|
|
99
|
+
| **Order** (11) | Get · Get Custom Fields · Get Comments · Get Calls · Get Many Tags · Get Cancel Reasons · Update · Update Custom Fields · Add Positions · Remove Positions · Add Comment |
|
|
100
|
+
| **Offer** (3) | Get · Get Many · Get Many Tags |
|
|
101
|
+
| **School** (5) | Get Many Groups · Get Many Departments · Get Many Trainings · Get Many Personal Managers · Get Survey Answers |
|
|
102
|
+
| **Dialog** (5) | Add Comment · Add Note · Change Department · Close · Get History |
|
|
103
|
+
| **HelpDesk Ticket** (5) | Add Comment · Add Note · Change Department · Close · Get History |
|
|
104
|
+
| **Lesson** (3) | Get Many Answers · Add Comment to Answer · Set Answer Status |
|
|
105
|
+
| **Webinar** (5) | Get Many · Get Many by IDs · Add Comment · Moderate Comment · Moderate User |
|
|
106
|
+
| **Call** (2) | Set Description · Set Transcription |
|
|
107
|
+
| **Webhook** (2) | Subscribe · Unsubscribe |
|
|
108
|
+
|
|
109
|
+
Dropdowns read the live account wherever the API publishes a list: user groups, departments,
|
|
110
|
+
personal managers, offers, cancellation reasons and webinars. Where it publishes none —
|
|
111
|
+
lessons, surveys, products, diploma templates, custom fields — the field is a plain input and
|
|
112
|
+
says so.
|
|
113
|
+
|
|
114
|
+
There is no listing of users or of orders anywhere in this API, which is why the node has no
|
|
115
|
+
"Get Many Users": a user is reached by ID, e-mail, phone or messenger chat ID, an order by its
|
|
116
|
+
ID or through its buyer. Reading them in bulk is the Legacy node's export.
|
|
117
|
+
|
|
118
|
+
Two things the API does that are easy to be caught by, and which the node states in the
|
|
119
|
+
operation description rather than leaving to discovery:
|
|
120
|
+
|
|
121
|
+
- **Set Groups replaces the whole membership list.** Add to Groups and Remove From Groups
|
|
122
|
+
are the incremental pair.
|
|
123
|
+
- **Call → Set Description and Set Transcription overwrite.** A second call replaces the
|
|
124
|
+
text rather than appending to it, so a loop keeps only the last value.
|
|
125
|
+
|
|
126
|
+
### Naming a user
|
|
127
|
+
|
|
128
|
+
Most user operations take one of three identifiers, and the node asks which one you mean
|
|
129
|
+
rather than letting you fill in two and leaving the server to choose:
|
|
130
|
+
|
|
131
|
+
- **User ID** — unambiguous, and the only form every endpoint accepts;
|
|
132
|
+
- **Email** — when the ID is unknown;
|
|
133
|
+
- **Phone** — documented for the write endpoints and for Get. The other reads may ignore it
|
|
134
|
+
and answer as though no user was named.
|
|
135
|
+
|
|
136
|
+
### Custom fields
|
|
137
|
+
|
|
138
|
+
The Tech API reads custom fields **by name** and writes them **by numeric ID**, and no
|
|
139
|
+
method in it lists those IDs. Use the Legacy node's **Custom Field → Get Many** to look
|
|
140
|
+
them up once; the ID is stable.
|
|
141
|
+
|
|
142
|
+
## GetCourse Legacy node
|
|
143
|
+
|
|
144
|
+
The account Import/Export API.
|
|
145
|
+
|
|
146
|
+
| Resource | Operation | What it does |
|
|
147
|
+
|---|---|---|
|
|
148
|
+
| **User** | Import | Creates the person, or updates them when **Update Existing** is on. Groups given here are added to the ones they are already in. |
|
|
149
|
+
| | Replace Groups | Sets the whole membership list — every group not named is removed. Needs the numeric user ID. |
|
|
150
|
+
| **Order** | Import | Creates the order and the buyer with it. Repeating it with the same order number edits that order instead. |
|
|
151
|
+
| | Set Status | Moves an existing order to another status. |
|
|
152
|
+
| **Export** | Export and Wait | Starts the job, waits for GetCourse to build the file, returns the rows. |
|
|
153
|
+
| | Start | Returns the export ID only. |
|
|
154
|
+
| | Check Status | Whether the file is ready, its column list and its row count — without the rows. |
|
|
155
|
+
| | Get Result | The rows of a finished export, or a report that it is still building. |
|
|
156
|
+
| **Group** | Get Many | Every group in the account, with its ID and when someone was last added. Answers directly, with no export job. |
|
|
157
|
+
| **Custom Field** | Get Many | The custom-field dictionary: ID, title, type and the entity each field belongs to. The only listing either API publishes. |
|
|
158
|
+
|
|
159
|
+
### Importing an order
|
|
160
|
+
|
|
161
|
+
The minimum GetCourse accepts is the buyer's e-mail plus **either** an Offer ID **or** an
|
|
162
|
+
offer code (or product title) together with an amount. Editing an existing order needs the
|
|
163
|
+
order number as well. An order carries one offer per request: to add a second, import again
|
|
164
|
+
with the same order number and **Append Offers** switched on.
|
|
165
|
+
|
|
166
|
+
An import is metered. Creating objects counts against a monthly allowance that depends on
|
|
167
|
+
the account plan; updating them does not. GetCourse says plainly that this API is for
|
|
168
|
+
importing data, not for reacting to things — for that, use the Trigger.
|
|
169
|
+
|
|
170
|
+
## GetCourse Trigger
|
|
171
|
+
|
|
172
|
+
GetCourse has two unrelated webhook systems, and the trigger's **Source** picks between
|
|
173
|
+
them.
|
|
174
|
+
|
|
175
|
+
### Source: GetCourse Process
|
|
176
|
+
|
|
177
|
+
Works on any paid account and needs no developer key. Copy the node's webhook URL, then in
|
|
178
|
+
GetCourse create a process with the **«Вызвать URL»** operation pointing at it — method
|
|
179
|
+
POST, body `json` or `x-www-form-urlencoded`.
|
|
180
|
+
|
|
181
|
+
There is **no fixed payload**: the field names and the field set are whatever the person
|
|
182
|
+
configuring the process types in, built from placeholders like `{object.email}` in a user
|
|
183
|
+
process and `{object.user.email}` in an order process. The node therefore passes the body
|
|
184
|
+
through unchanged and validates nothing.
|
|
185
|
+
|
|
186
|
+
### Source: Tech API Subscription
|
|
187
|
+
|
|
188
|
+
The node subscribes itself through `POST /set-uri` when the workflow is activated and
|
|
189
|
+
unsubscribes when it is deactivated. Pick one **Event Object** and the events under it.
|
|
190
|
+
|
|
191
|
+
One node listens to one event object on purpose. An Входящие message and a HelpDesk message
|
|
192
|
+
arrive as byte-for-byte identical bodies — same `event_id`, same `dialog_id` field name,
|
|
193
|
+
same everything — so the only thing that can tell them apart is which subscription
|
|
194
|
+
delivered them. Splitting by object keeps every delivery attributable, and the node fills
|
|
195
|
+
in an `eventType` accordingly.
|
|
196
|
+
|
|
197
|
+
The subscription belongs to the developer key, not to the workflow: deleting the node
|
|
198
|
+
without deactivating it first leaves GetCourse posting into a dead URL.
|
|
199
|
+
|
|
200
|
+
### Verifying deliveries
|
|
201
|
+
|
|
202
|
+
GetCourse signs nothing it sends, over either mechanism: if the address leaks, anyone can
|
|
203
|
+
post to it.
|
|
204
|
+
|
|
205
|
+
For **GetCourse Process** there is something to be done about that. Under **Verification**
|
|
206
|
+
the node can require a shared secret in a header or a query parameter, and answers 403
|
|
207
|
+
without starting the workflow when it is missing — add the same header in the «Вызвать URL»
|
|
208
|
+
settings of the process.
|
|
209
|
+
|
|
210
|
+
For a **Tech API Subscription** there is not. GetCourse composes the delivery itself and
|
|
211
|
+
sends a body and nothing else, so no secret of yours can be attached to it and the setting is
|
|
212
|
+
not offered. The URL is the only thing keeping those events private.
|
|
213
|
+
|
|
214
|
+
Nor can a subscription be tested with n8n's **Listen for test event**: `set-uri` holds one
|
|
215
|
+
address per event, so subscribing the temporary test URL would replace the live one and
|
|
216
|
+
unsubscribing it afterwards would take the running workflow off the air. The node refuses
|
|
217
|
+
that rather than doing it. Activate the workflow to receive real events.
|
|
218
|
+
|
|
219
|
+
## Exporting data
|
|
220
|
+
|
|
221
|
+
An export is asynchronous: one call starts the job and returns an ID, a second call either
|
|
222
|
+
says "not ready" or hands over the whole table. The node offers that as one operation or as
|
|
223
|
+
three, and both shapes are legitimate.
|
|
224
|
+
|
|
225
|
+
**One node.** *Export → Export and Wait* does the lot. Simple, and right for a nightly
|
|
226
|
+
report — but it holds the execution open while it waits, and a restart of n8n loses the
|
|
227
|
+
wait.
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
[GetCourse Legacy] Export → Export and Wait → one item per row
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**Three nodes.** *Start*, then an n8n **Wait** node, then *Get Result*. The wait costs no
|
|
234
|
+
execution time and survives a restart, which is what a large export needs. Set *Get
|
|
235
|
+
Result*'s **On Not Ready** to *Return Status* and an IF node can loop back:
|
|
236
|
+
|
|
237
|
+
```
|
|
238
|
+
[Start] → export_id
|
|
239
|
+
↓
|
|
240
|
+
[Wait 30s]
|
|
241
|
+
↓
|
|
242
|
+
[Get Result] On Not Ready: Return Status
|
|
243
|
+
↓
|
|
244
|
+
[IF ready == false] ──yes──→ back to [Wait 30s]
|
|
245
|
+
│ no
|
|
246
|
+
↓ one item per row
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
*Check Status* exists for a chain that wants an explicit readiness step. It is honest about
|
|
250
|
+
its cost: checking and fetching are the same request underneath, so a Check-then-Get chain
|
|
251
|
+
spends one request more per loop than *Get Result* alone.
|
|
252
|
+
|
|
253
|
+
An export needs **at least one filter** — GetCourse refuses to build a file without one,
|
|
254
|
+
and an account-wide export of a school with years of history is tens of megabytes. Split
|
|
255
|
+
long periods into several runs.
|
|
256
|
+
|
|
257
|
+
Whenever *Export and Wait* gives up or fails part-way through — the file is still building,
|
|
258
|
+
or the account's request budget ran out mid-poll — the error names the export ID. Nothing is
|
|
259
|
+
lost: the job goes on building on GetCourse's side, and a *Get Result* with that ID collects
|
|
260
|
+
it later, in this run or a later one. That matters because there is no method that lists
|
|
261
|
+
exports, so an ID nobody wrote down cannot be recovered.
|
|
262
|
+
|
|
263
|
+
### Dates and timezones
|
|
264
|
+
|
|
265
|
+
Filter dates are sent as whole days, worked out in the **workflow's** timezone — the one
|
|
266
|
+
n8n shows in the workflow settings, not the account's. A school in a different zone can see
|
|
267
|
+
the boundary fall a few hours out; set the workflow timezone to the school's to line them up.
|
|
268
|
+
|
|
269
|
+
A date written the Russian way, `01.03.2026`, is read as the first of March. That has to be
|
|
270
|
+
said because the obvious implementation gets it wrong: JavaScript's own parser reads the same
|
|
271
|
+
string as the third of January, and only for the first twelve days of a month — from the
|
|
272
|
+
thirteenth it fails instead. Anything the node cannot read with certainty is refused by name
|
|
273
|
+
rather than guessed at, because an export whose filter is ignored returns the whole account.
|
|
274
|
+
|
|
275
|
+
### The shape of the result
|
|
276
|
+
|
|
277
|
+
GetCourse answers with a table, not a list of objects: a column list and an array of arrays.
|
|
278
|
+
The node zips them, one output item per row. The column set is account-specific — every
|
|
279
|
+
custom field is spliced into the middle of the row — so nothing may be read by position.
|
|
280
|
+
|
|
281
|
+
Column titles are mostly Russian, with spaces and punctuation: `$json["Создан"]`,
|
|
282
|
+
`$json["ID партнера"]`. A few arrive in Latin — `utm_source`, `VK-ID`, and the five
|
|
283
|
+
`gc_system_user_utm_*` fields GetCourse adds to every account. Set **Options → Column
|
|
284
|
+
Names → Transliterated** to get `sozdan` instead, at the cost of exactness. An export whose
|
|
285
|
+
filter matches nothing is not an error: it returns the full column list and no rows, so the
|
|
286
|
+
node emits no items. Every cell arrives as a string, including money in Russian format
|
|
287
|
+
(`12 000,00`, sometimes with a non-breaking space) — the node does not coerce.
|
|
288
|
+
|
|
289
|
+
## Limits
|
|
290
|
+
|
|
291
|
+
| | |
|
|
292
|
+
|---|---|
|
|
293
|
+
| Export API | **100 requests per two hours per account**, status checks included. One export at a time per account. |
|
|
294
|
+
| Import API | A monthly allowance on **creating** objects, set by the account plan. Updates do not count. |
|
|
295
|
+
| Tech API | No published rate limit. The credential throttles to 5 requests per second by default as a precaution. |
|
|
296
|
+
|
|
297
|
+
The export budget is enforced by this package across the whole n8n process, per account
|
|
298
|
+
host, so several workflows hitting one account add up to one budget rather than racing.
|
|
299
|
+
|
|
300
|
+
The one-export-at-a-time rule deserves planning for rather than reacting to. It is
|
|
301
|
+
account-wide, so anything else exporting from the same school holds it — on a busy account
|
|
302
|
+
with other integrations, a start refused with «Уже запущен один экспорт» is the normal case,
|
|
303
|
+
not the rare one. Give the Export node a single item, or loop items through a Wait node, and
|
|
304
|
+
turn on **Settings → On Error → Continue** so a refusal does not discard the export IDs
|
|
305
|
+
earlier items already returned.
|
|
306
|
+
|
|
307
|
+
## Data quirks worth knowing
|
|
308
|
+
|
|
309
|
+
Observed in the wild rather than documented. The nodes do not silently correct any of them.
|
|
310
|
+
|
|
311
|
+
- A set-uri delivery arrives **wrapped**: `{"json": { … }}`. The trigger unwraps it, so
|
|
312
|
+
`$json.deal.status` is what you write, not `$json.json.deal.status`.
|
|
313
|
+
- `deal.isPayed` in a webhook is sometimes `0`/`1` and sometimes a boolean — and is `0` in a
|
|
314
|
+
`dealPaid` event even for a priced order that was just marked paid, not only for a free one.
|
|
315
|
+
- **`ts` is not the event's time.** It is the order's `createdAt`, and it is identical in
|
|
316
|
+
every delivery about that order however far apart the events were — four events minutes
|
|
317
|
+
apart all carried one `ts`. Do not deduplicate or order on it.
|
|
318
|
+
- **`ts` is not UTC either, despite ending in `Z`.** It is the account's local time with a
|
|
319
|
+
`Z` appended: an account three hours ahead sent `10:52:21Z` with a `ts64` of `1788681141`,
|
|
320
|
+
which is `07:52:21Z`. Use `ts64` when the real instant matters.
|
|
321
|
+
- `deal.status` takes the literal string `"false"`, which is GetCourse's «Ложный» status.
|
|
322
|
+
- `deal.payedValue` can be fractional and **less** than `cost` while the status is `payed`.
|
|
323
|
+
- `answer.id` arrives as a string with single quotes inside it: `"'501283094'"`.
|
|
324
|
+
- `comment.files` is a **string containing JSON** and needs parsing.
|
|
325
|
+
- `additional_fields[].required` is sometimes a boolean and sometimes the string `"1"`.
|
|
326
|
+
- A paid order fires **both** `dealPaid` and `dealStatusChanged` — confirmed on a live
|
|
327
|
+
account, as two separate deliveries whose bodies differ in `eventType` and nothing else.
|
|
328
|
+
Deduplicate if you act on both.
|
|
329
|
+
- Deliveries carry **no signature and no authentication header of any kind**, and they arrive
|
|
330
|
+
from more than one address — two different source IPs across four consecutive events — so
|
|
331
|
+
neither a shared secret nor an IP allowlist is available. The secrecy of the URL is the
|
|
332
|
+
only thing protecting a subscription.
|
|
333
|
+
- Export cells are always strings, dates as `YYYY-MM-DD HH:MM:SS` in the account's timezone.
|
|
334
|
+
|
|
335
|
+
## Compatibility
|
|
336
|
+
|
|
337
|
+
Built against n8n 2.x with `@n8n/node-cli`. No runtime dependencies.
|
|
338
|
+
|
|
339
|
+
## Feedback and bugs
|
|
340
|
+
|
|
341
|
+
Bug reports and ideas are welcome — open an issue:
|
|
342
|
+
[github.com/zenland-dev/n8n-nodes-getcourse/issues](https://github.com/zenland-dev/n8n-nodes-getcourse/issues).
|
|
343
|
+
|
|
344
|
+
What makes a report quick to act on:
|
|
345
|
+
|
|
346
|
+
- your n8n version and the version of this package;
|
|
347
|
+
- which node — GetCourse, GetCourse Legacy or the Trigger — and which operation;
|
|
348
|
+
- what GetCourse answered. It likes to reply `200 OK` with `success: false`, so the body
|
|
349
|
+
matters more than the status code; strip the keys before pasting it;
|
|
350
|
+
- for an export, the export id and whether it ever left the `processing` state;
|
|
351
|
+
- for the trigger, the source — a GetCourse process or a Tech API subscription — and one
|
|
352
|
+
sample payload with the personal data removed.
|
|
353
|
+
|
|
354
|
+
GetCourse's own quirks are collected in [Data quirks worth knowing](#data-quirks-worth-knowing);
|
|
355
|
+
if you hit a new one, it belongs in an issue too — the list grows from them.
|
|
356
|
+
|
|
357
|
+
## License
|
|
358
|
+
|
|
359
|
+
[MIT](LICENSE.md)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Icon, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare const ACCOUNT_BASE_URL: string;
|
|
3
|
+
export declare class GetCourseApi implements ICredentialType {
|
|
4
|
+
name: string;
|
|
5
|
+
displayName: string;
|
|
6
|
+
documentationUrl: string;
|
|
7
|
+
icon: Icon;
|
|
8
|
+
properties: INodeProperties[];
|
|
9
|
+
test: ICredentialTestRequest;
|
|
10
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GetCourseApi = exports.ACCOUNT_BASE_URL = void 0;
|
|
4
|
+
const accountAddress_1 = require("./accountAddress");
|
|
5
|
+
exports.ACCOUNT_BASE_URL = `=https://{{ ${(0, accountAddress_1.accountHostExpression)('$credentials')} }}`;
|
|
6
|
+
class GetCourseApi {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.name = 'getCourseApi';
|
|
9
|
+
this.displayName = 'GetCourse Account API';
|
|
10
|
+
this.documentationUrl = 'https://getcourse.ru/help/api';
|
|
11
|
+
this.icon = {
|
|
12
|
+
light: 'file:../icons/getcourse.svg',
|
|
13
|
+
dark: 'file:../icons/getcourse.dark.svg',
|
|
14
|
+
};
|
|
15
|
+
this.properties = [
|
|
16
|
+
...accountAddress_1.accountAddressProperties,
|
|
17
|
+
{
|
|
18
|
+
displayName: 'Secret Key',
|
|
19
|
+
name: 'secretKey',
|
|
20
|
+
type: 'string',
|
|
21
|
+
typeOptions: { password: true },
|
|
22
|
+
default: '',
|
|
23
|
+
required: true,
|
|
24
|
+
description: 'Секретный ключ API аккаунта. Generate it in Профиль → Настройки аккаунта → АПИ. A read-only key is enough for exports and for reading the custom-field dictionary; imports need a key with write access.',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
displayName: 'Export Requests per Hour',
|
|
28
|
+
name: 'exportRequestsPerHour',
|
|
29
|
+
type: 'number',
|
|
30
|
+
typeOptions: { minValue: 1, maxValue: 50 },
|
|
31
|
+
default: 45,
|
|
32
|
+
description: 'How many Export API calls this account may make per hour. GetCourse allows 100 per two hours and counts every status check, so the default leaves room for a second workflow. Exceeding it answers 903 for everyone using the account.',
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
this.test = {
|
|
36
|
+
request: {
|
|
37
|
+
baseURL: exports.ACCOUNT_BASE_URL,
|
|
38
|
+
url: '/pl/api/account/fields',
|
|
39
|
+
method: 'POST',
|
|
40
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
41
|
+
body: '=action=get&key={{ encodeURIComponent($credentials.secretKey) }}',
|
|
42
|
+
disableFollowRedirect: true,
|
|
43
|
+
},
|
|
44
|
+
rules: [
|
|
45
|
+
{
|
|
46
|
+
type: 'responseSuccessBody',
|
|
47
|
+
properties: {
|
|
48
|
+
key: 'success',
|
|
49
|
+
value: false,
|
|
50
|
+
message: 'GetCourse refused the key. Check the secret key and the account address, and that the account is on a paid plan — the Import/Export API is switched off on the trial one. If the account redirects its GetCourse address to a domain of its own, switch this credential to Custom Domain: the API answers only on that domain.',
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.GetCourseApi = GetCourseApi;
|
|
58
|
+
//# sourceMappingURL=GetCourseApi.credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GetCourseApi.credentials.js","sourceRoot":"","sources":["../../credentials/GetCourseApi.credentials.ts"],"names":[],"mappings":";;;AAEA,qDAAmF;AAGtE,QAAA,gBAAgB,GAAG,eAAe,IAAA,sCAAqB,EAAC,cAAc,CAAC,KAAK,CAAC;AAY1F,MAAa,YAAY;IAAzB;QACC,SAAI,GAAG,cAAc,CAAC;QAEtB,gBAAW,GAAG,uBAAuB,CAAC;QAEtC,qBAAgB,GAAG,+BAA+B,CAAC;QAEnD,SAAI,GAAS;YACZ,KAAK,EAAE,6BAA6B;YACpC,IAAI,EAAE,kCAAkC;SACxC,CAAC;QAEF,eAAU,GAAsB;YAC/B,GAAG,yCAAwB;YAC3B;gBACC,WAAW,EAAE,YAAY;gBACzB,IAAI,EAAE,WAAW;gBACjB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EACV,0MAA0M;aAC3M;YACD;gBACC,WAAW,EAAE,0BAA0B;gBACvC,IAAI,EAAE,uBAAuB;gBAC7B,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;gBAC1C,OAAO,EAAE,EAAE;gBACX,WAAW,EACV,wOAAwO;aACzO;SACD,CAAC;QAUF,SAAI,GAA2B;YAC9B,OAAO,EAAE;gBACR,OAAO,EAAE,wBAAgB;gBACzB,GAAG,EAAE,wBAAwB;gBAC7B,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;gBAChE,IAAI,EAAE,kEAAkE;gBAMxE,qBAAqB,EAAE,IAAI;aAC3B;YACD,KAAK,EAAE;gBACN;oBACC,IAAI,EAAE,qBAAqB;oBAC3B,UAAU,EAAE;wBACX,GAAG,EAAE,SAAS;wBACd,KAAK,EAAE,KAAK;wBACZ,OAAO,EACN,gUAAgU;qBACjU;iBACD;aACD;SACD,CAAC;IACH,CAAC;CAAA;AArED,oCAqEC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { IAuthenticateGeneric, Icon, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare const ACCOUNT_BASE_URL: string;
|
|
3
|
+
export declare class GetCourseTechApi implements ICredentialType {
|
|
4
|
+
name: string;
|
|
5
|
+
displayName: string;
|
|
6
|
+
documentationUrl: string;
|
|
7
|
+
icon: Icon;
|
|
8
|
+
properties: INodeProperties[];
|
|
9
|
+
authenticate: IAuthenticateGeneric;
|
|
10
|
+
test: ICredentialTestRequest;
|
|
11
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GetCourseTechApi = exports.ACCOUNT_BASE_URL = void 0;
|
|
4
|
+
const accountAddress_1 = require("./accountAddress");
|
|
5
|
+
exports.ACCOUNT_BASE_URL = `=https://{{ ${(0, accountAddress_1.accountHostExpression)('$credentials')} }}`;
|
|
6
|
+
class GetCourseTechApi {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.name = 'getCourseTechApi';
|
|
9
|
+
this.displayName = 'GetCourse Tech API';
|
|
10
|
+
this.documentationUrl = 'https://getcourse.ru/pl/postback/redoc';
|
|
11
|
+
this.icon = {
|
|
12
|
+
light: 'file:../icons/getcourse.svg',
|
|
13
|
+
dark: 'file:../icons/getcourse.dark.svg',
|
|
14
|
+
};
|
|
15
|
+
this.properties = [
|
|
16
|
+
...accountAddress_1.accountAddressProperties,
|
|
17
|
+
{
|
|
18
|
+
displayName: 'Developer Key',
|
|
19
|
+
name: 'developerApiKey',
|
|
20
|
+
type: 'string',
|
|
21
|
+
typeOptions: { password: true },
|
|
22
|
+
default: '',
|
|
23
|
+
required: true,
|
|
24
|
+
description: 'Ключ разработчика. Issued to the integrator by GetCourse after the form at getcourse.ru/issuedeveloperkey. It is the same key for every school you integrate.',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
displayName: 'School API Key',
|
|
28
|
+
name: 'schoolApiKey',
|
|
29
|
+
type: 'string',
|
|
30
|
+
typeOptions: { password: true },
|
|
31
|
+
default: '',
|
|
32
|
+
required: true,
|
|
33
|
+
description: 'Ключ АПИ школы. Handed out by the school itself, one per account. It is documented as a different key from the account Secret Key the legacy Import/Export API uses, but that Secret Key was accepted here on every account tried — so if the school cannot find a separate one, the Secret Key is worth pasting in before chasing support.',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
displayName: 'Requests per Second',
|
|
37
|
+
name: 'requestsPerSecond',
|
|
38
|
+
type: 'number',
|
|
39
|
+
typeOptions: { minValue: 1, maxValue: 50 },
|
|
40
|
+
default: 5,
|
|
41
|
+
description: 'A client-side throttle, not a documented platform limit. GetCourse publishes no rate for the Tech API, so this keeps a busy workflow from finding out where the ceiling is the hard way.',
|
|
42
|
+
},
|
|
43
|
+
accountAddress_1.pinnedHttpRequestDomains,
|
|
44
|
+
];
|
|
45
|
+
this.authenticate = {
|
|
46
|
+
type: 'generic',
|
|
47
|
+
properties: {
|
|
48
|
+
headers: {
|
|
49
|
+
Authorization: '=Bearer {{$credentials.developerApiKey}}_{{$credentials.schoolApiKey}}',
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
this.test = {
|
|
54
|
+
request: {
|
|
55
|
+
baseURL: exports.ACCOUNT_BASE_URL,
|
|
56
|
+
url: '/pl/api/v1/common/get-departments',
|
|
57
|
+
disableFollowRedirect: true,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.GetCourseTechApi = GetCourseTechApi;
|
|
63
|
+
//# sourceMappingURL=GetCourseTechApi.credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GetCourseTechApi.credentials.js","sourceRoot":"","sources":["../../credentials/GetCourseTechApi.credentials.ts"],"names":[],"mappings":";;;AAQA,qDAI0B;AAGb,QAAA,gBAAgB,GAAG,eAAe,IAAA,sCAAqB,EAAC,cAAc,CAAC,KAAK,CAAC;AAU1F,MAAa,gBAAgB;IAA7B;QACC,SAAI,GAAG,kBAAkB,CAAC;QAE1B,gBAAW,GAAG,oBAAoB,CAAC;QAEnC,qBAAgB,GAAG,wCAAwC,CAAC;QAE5D,SAAI,GAAS;YACZ,KAAK,EAAE,6BAA6B;YACpC,IAAI,EAAE,kCAAkC;SACxC,CAAC;QAEF,eAAU,GAAsB;YAC/B,GAAG,yCAAwB;YAC3B;gBACC,WAAW,EAAE,eAAe;gBAC5B,IAAI,EAAE,iBAAiB;gBACvB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EACV,+JAA+J;aAChK;YACD;gBACC,WAAW,EAAE,gBAAgB;gBAC7B,IAAI,EAAE,cAAc;gBACpB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EACV,6UAA6U;aAC9U;YACD;gBACC,WAAW,EAAE,qBAAqB;gBAClC,IAAI,EAAE,mBAAmB;gBACzB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;gBAC1C,OAAO,EAAE,CAAC;gBACV,WAAW,EACV,0LAA0L;aAC3L;YACD,yCAAwB;SACxB,CAAC;QAEF,iBAAY,GAAyB;YACpC,IAAI,EAAE,SAAS;YACf,UAAU,EAAE;gBACX,OAAO,EAAE;oBACR,aAAa,EAAE,wEAAwE;iBACvF;aACD;SACD,CAAC;QAMF,SAAI,GAA2B;YAC9B,OAAO,EAAE;gBACR,OAAO,EAAE,wBAAgB;gBACzB,GAAG,EAAE,mCAAmC;gBAGxC,qBAAqB,EAAE,IAAI;aAC3B;SACD,CAAC;IACH,CAAC;CAAA;AApED,4CAoEC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare const ACCOUNT_DOMAINS: readonly ["getcourse.ru", "getcourse.io"];
|
|
3
|
+
export declare function accountHostExpression(ref: string): string;
|
|
4
|
+
export declare function accountBaseUrl(credentials: {
|
|
5
|
+
accountMode?: unknown;
|
|
6
|
+
subdomain?: unknown;
|
|
7
|
+
domain?: unknown;
|
|
8
|
+
customDomain?: unknown;
|
|
9
|
+
}): string;
|
|
10
|
+
export declare const accountAddressProperties: INodeProperties[];
|
|
11
|
+
export declare const pinnedHttpRequestDomains: INodeProperties;
|