@awesomate/hosting-mcp 0.51.0 → 0.53.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/dist/index.js +21 -13
- package/package.json +1 -1
- package/skill/CHANGELOG.json +14 -0
- package/skill/awesomate-portals/SKILL.md +13 -6
package/dist/index.js
CHANGED
|
@@ -42804,17 +42804,19 @@ var crmAttribute = external_exports.object({
|
|
|
42804
42804
|
choices: external_exports.array(external_exports.string().max(100)).max(200).optional().describe("required for choice / choices"),
|
|
42805
42805
|
required: external_exports.boolean().optional(),
|
|
42806
42806
|
sensitivity: external_exports.enum(["ordinary", "personal", "sensitive"]).optional().describe("sensitive values are never readable by AI"),
|
|
42807
|
-
readable_by_ai: external_exports.boolean().optional().describe("default false: only readable attributes reach awesomate_crm_rows")
|
|
42807
|
+
readable_by_ai: external_exports.boolean().optional().describe("default false: only readable attributes reach awesomate_crm_rows"),
|
|
42808
|
+
visible_to: external_exports.array(external_exports.string().max(31)).max(10).nullable().optional().describe("which of an app's signed-in roles see it, e.g. ['staff']; leave out for everyone who can read the record")
|
|
42808
42809
|
});
|
|
42809
42810
|
server.registerTool(
|
|
42810
42811
|
"awesomate_crm_kinds",
|
|
42811
42812
|
{
|
|
42812
42813
|
annotations: annotate("awesomate_crm_kinds", MUTATING),
|
|
42813
|
-
description: "The kinds of app data in the client's own database (the tables an app keeps: jobs, memos, bookings, messages), created directly from here on Support Plus and above. action 'list': every kind with its attributes and links. 'define' {key, label?, label_plural?, attributes, links?}: a new kind; links: [{key, to, label?, required?}] where to is 'contact' or a kind already made, and each shows as <key>_id. 'add_attribute' {kind, attribute}. 'archive_attribute' {kind, key}: leaves the views, values kept. 'archive' {kind}: kept, restorable. No migration and no SQL: a kind is registry rows plus generated views. Business things whose values must be traced to a source (a property, an installed system) are 'tracked' kinds the owner accepts in the hub; they are refused here. Mark an attribute readable_by_ai only when the owner wants Claude and agents to see it, and never for anything sensitive. 'set_access' {kind, access} (or access on define): who among the people signed in to the account's apps (awesomate_crm_apps) may read and change records of this kind, by their role: {read: {<role>: <rule>}, write: {<role>: <rule>}}. A rule is all, none, own (records they created), or linked:<link path ending at a contact> (linked:customer: jobs whose customer is them; linked:job.customer: memos on their jobs), joined with |. A role with no rule gets nothing; the default lets owner and staff do everything and members nothing. A write must leave the record inside the person's rule. Confirm the design with the user before defining: a kind is part of their data, not scratch space.",
|
|
42814
|
+
description: "The kinds of app data in the client's own database (the tables an app keeps: jobs, memos, bookings, messages), created directly from here on Support Plus and above. action 'list': every kind with its attributes and links. 'define' {key, label?, label_plural?, attributes, links?}: a new kind; links: [{key, to, label?, required?}] where to is 'contact' or a kind already made, and each shows as <key>_id. 'add_attribute' {kind, attribute}. 'archive_attribute' {kind, key}: leaves the views, values kept. 'set_visibility' {kind, key, visible_to}: which of an app's signed-in roles see that attribute (['staff'] for a cost or an internal note on a customer's job; null for everyone who can read the record; [] for none of them). Others read it as null and cannot write it; the database enforces it, and the account, Claude and hooks always see every attribute. 'archive' {kind}: kept, restorable. No migration and no SQL: a kind is registry rows plus generated views. Business things whose values must be traced to a source (a property, an installed system) are 'tracked' kinds the owner accepts in the hub; they are refused here. Mark an attribute readable_by_ai only when the owner wants Claude and agents to see it, and never for anything sensitive. 'set_access' {kind, access} (or access on define): who among the people signed in to the account's apps (awesomate_crm_apps) may read and change records of this kind, by their role: {read: {<role>: <rule>}, write: {<role>: <rule>}}. A rule is all, none, own (records they created), or linked:<link path ending at a contact> (linked:customer: jobs whose customer is them; linked:job.customer: memos on their jobs), joined with |. A role with no rule gets nothing; the default lets owner and staff do everything and members nothing. A write must leave the record inside the person's rule. Confirm the design with the user before defining: a kind is part of their data, not scratch space.",
|
|
42814
42815
|
inputSchema: {
|
|
42815
|
-
action: external_exports.enum(["list", "define", "add_attribute", "archive_attribute", "archive", "set_access"]),
|
|
42816
|
-
kind: external_exports.string().max(41).optional().describe("the kind to change (add_attribute, archive_attribute, archive, set_access)"),
|
|
42817
|
-
key: external_exports.string().max(41).optional().describe("define: the new kind; archive_attribute: the attribute"),
|
|
42816
|
+
action: external_exports.enum(["list", "define", "add_attribute", "archive_attribute", "archive", "set_access", "set_visibility"]),
|
|
42817
|
+
kind: external_exports.string().max(41).optional().describe("the kind to change (add_attribute, archive_attribute, archive, set_access, set_visibility)"),
|
|
42818
|
+
key: external_exports.string().max(41).optional().describe("define: the new kind; archive_attribute, set_visibility: the attribute"),
|
|
42819
|
+
visible_to: external_exports.array(external_exports.string().max(31)).max(10).nullable().optional().describe("set_visibility: the roles that see it, or null for everyone"),
|
|
42818
42820
|
label: external_exports.string().max(80).optional(),
|
|
42819
42821
|
label_plural: external_exports.string().max(80).optional(),
|
|
42820
42822
|
attributes: external_exports.array(crmAttribute).max(60).optional(),
|
|
@@ -42826,7 +42828,7 @@ server.registerTool(
|
|
|
42826
42828
|
}).optional().describe("define / set_access: {read: {<role>: <rule>}, write: {<role>: <rule>}}")
|
|
42827
42829
|
}
|
|
42828
42830
|
},
|
|
42829
|
-
async ({ action, kind, key, label, label_plural, attributes, links, attribute, access }) => {
|
|
42831
|
+
async ({ action, kind, key, label, label_plural, attributes, links, attribute, access, visible_to }) => {
|
|
42830
42832
|
try {
|
|
42831
42833
|
const cfg = requireConfig();
|
|
42832
42834
|
if (action === "list") return textResult(await hubGet(cfg, "/api/my-crm/v1/kinds"));
|
|
@@ -42840,6 +42842,10 @@ server.registerTool(
|
|
|
42840
42842
|
return textResult(await hubPut(cfg, `/api/my-crm/v1/kinds/${k}/access`, { access }));
|
|
42841
42843
|
}
|
|
42842
42844
|
if (action === "add_attribute") return textResult(await hubPost(cfg, `/api/my-crm/v1/kinds/${k}/attributes`, { attribute }));
|
|
42845
|
+
if (action === "set_visibility") {
|
|
42846
|
+
if (!key || visible_to === void 0) return errorResult(new Error("set_visibility needs key (the attribute) and visible_to (a list of roles, or null for everyone)."));
|
|
42847
|
+
return textResult(await hubPut(cfg, `/api/my-crm/v1/kinds/${k}/attributes/${encodeURIComponent(key)}/visibility`, { visible_to }));
|
|
42848
|
+
}
|
|
42843
42849
|
if (action === "archive_attribute") {
|
|
42844
42850
|
if (!key) return errorResult(new Error("archive_attribute needs key, the attribute."));
|
|
42845
42851
|
return textResult(await hubDelete(cfg, `/api/my-crm/v1/kinds/${k}/attributes/${encodeURIComponent(key)}`));
|
|
@@ -42887,13 +42893,14 @@ server.registerTool(
|
|
|
42887
42893
|
"awesomate_crm_apps",
|
|
42888
42894
|
{
|
|
42889
42895
|
annotations: annotate("awesomate_crm_apps", MUTATING),
|
|
42890
|
-
description: "The account's own apps (a client portal, a members' app) whose users sign in by email link and then read and change only what each kind's access rules allow them (awesomate_crm_kinds set_access). Pro and above to create or change; reading is every plan. action 'list': each app with its publishable key, allowed origins, sign-up mode and default role. action 'create' {name, allowed_origins, sign_up?, default_role?}: name appears in the sign-in email; allowed_origins are the exact origins the app runs on (https://portal.example.com; http://localhost:5173 for development; capacitor://localhost for the mobile shell), with no path and no wildcard; sign_up 'invite' (default: only people added with awesomate_crm_app_users) or 'open' (anyone who uses the email link gets the default role). action 'update' {app_id, ...any of those, status?}: status 'disabled' signs everyone out of that app and stops its server keys. The publishable key (pk_...) is not a secret: it goes in the app's browser code, with @awesomate/sdk. Never put the account's own token (amt_pat_...) in browser code. Confirm origins and sign-up mode with the user: open sign-up lets strangers in under the default role. action 'customer_lookup' {app_id, roles?}: which roles in that app may look customers up (name, email and phone, by search or id, with @awesomate/sdk lookupCustomers) and so put a record under any customer, not only themselves. Without roles it reads the setting; roles ['staff'] switches it on for staff; [] switches it off. Never the app's default role (the one customers sign in with): that would show every customer to every other customer, and the hub refuses it. Off until the owner asks for it. SERVER KEYS (ak_...), for the app's own server or an n8n workflow, used with @awesomate/sdk createClient({ token: <key> }) or as a Bearer token on https://hub.awesomate.ai/api/sdk/v1/server: action 'keys' {app_id} lists them (never the secrets); 'create_key' {app_id, name, access: 'read'|'write', kinds?} makes one (kinds leaves it to those kinds, 'contact' to read contacts; leave it out for every kind) and returns the key ONCE: put it straight into the app server's environment (awesomate_app_set_env for an app hosted with us
|
|
42896
|
+
description: "The account's own apps (a client portal, a members' app) whose users sign in by email link and then read and change only what each kind's access rules allow them (awesomate_crm_kinds set_access). Pro and above to create or change; reading is every plan. action 'list': each app with its publishable key, allowed origins, sign-up mode and default role. action 'create' {name, allowed_origins, sign_up?, default_role?}: name appears in the sign-in email; allowed_origins are the exact origins the app runs on (https://portal.example.com; http://localhost:5173 for development; capacitor://localhost for the mobile shell), with no path and no wildcard; sign_up 'invite' (default: only people added with awesomate_crm_app_users) or 'open' (anyone who uses the email link gets the default role). action 'update' {app_id, ...any of those, status?}: status 'disabled' signs everyone out of that app and stops its server keys. The publishable key (pk_...) is not a secret: it goes in the app's browser code, with @awesomate/sdk. Never put the account's own token (amt_pat_...) in browser code. Confirm origins and sign-up mode with the user: open sign-up lets strangers in under the default role. action 'customer_lookup' {app_id, roles?}: which roles in that app may look customers up (name, email and phone, by search or id, with @awesomate/sdk lookupCustomers) and so put a record under any customer, not only themselves. Without roles it reads the setting; roles ['staff'] switches it on for staff; [] switches it off. Never the app's default role (the one customers sign in with): that would show every customer to every other customer, and the hub refuses it. Off until the owner asks for it. SERVER KEYS (ak_...), for the app's own server or an n8n workflow, used with @awesomate/sdk createClient({ token: <key> }) or as a Bearer token on https://hub.awesomate.ai/api/sdk/v1/server: action 'keys' {app_id} lists them (never the secrets); 'create_key' {app_id, name, access: 'read'|'write', kinds?} makes one (kinds leaves it to those kinds, 'contact' to read contacts; leave it out for every kind) and returns the key ONCE: put it straight into the app server's environment (awesomate_app_set_env for an app hosted with us) and never into browser code, a repository or a reply to the user. For an n8n workflow pass n8n_credential: true instead (prefer it): the hub puts the key into a Header Auth credential 'Awesomate app key: <name>' on their n8n (Authorization: Bearer, usable only towards the hub) and returns only its id and name, so the key never passes through you. 'revoke_key' {app_id, key_id} stops it at once, and removes a credential the hub made. A key reads every attribute of an app kind, contacts only as you read them, and writes need Support Plus and above. Prefer the narrowest key: read unless the server writes, and only the kinds it uses.",
|
|
42891
42897
|
inputSchema: {
|
|
42892
42898
|
action: external_exports.enum(["list", "create", "update", "keys", "create_key", "revoke_key", "customer_lookup"]),
|
|
42893
42899
|
app_id: external_exports.string().max(48).optional().describe("update, keys, create_key, revoke_key, customer_lookup: the app"),
|
|
42894
42900
|
access: external_exports.enum(["read", "write"]).optional().describe("create_key"),
|
|
42895
42901
|
kinds: external_exports.array(external_exports.string().max(41)).max(50).optional().describe("create_key: only these kinds (contact to read contacts); leave out for every kind"),
|
|
42896
42902
|
key_id: external_exports.string().max(64).optional().describe("revoke_key: from keys"),
|
|
42903
|
+
n8n_credential: external_exports.boolean().optional().describe("create_key: put the key into an n8n credential on their n8n instead of the answer"),
|
|
42897
42904
|
roles: external_exports.array(external_exports.string().max(31)).max(10).optional().describe("customer_lookup: the roles that may look customers up; [] switches it off; leave out to read"),
|
|
42898
42905
|
name: external_exports.string().max(80).optional(),
|
|
42899
42906
|
allowed_origins: external_exports.array(external_exports.string().max(200)).max(10).optional(),
|
|
@@ -42902,7 +42909,7 @@ server.registerTool(
|
|
|
42902
42909
|
status: external_exports.enum(["active", "disabled"]).optional().describe("update only")
|
|
42903
42910
|
}
|
|
42904
42911
|
},
|
|
42905
|
-
async ({ action, app_id, name, allowed_origins, sign_up, default_role, status, access, kinds, key_id, roles }) => {
|
|
42912
|
+
async ({ action, app_id, name, allowed_origins, sign_up, default_role, status, access, kinds, key_id, roles, n8n_credential }) => {
|
|
42906
42913
|
try {
|
|
42907
42914
|
const cfg = requireConfig();
|
|
42908
42915
|
if (action === "list") return textResult(await hubGet(cfg, "/api/my-crm/v1/apps"));
|
|
@@ -42920,7 +42927,7 @@ server.registerTool(
|
|
|
42920
42927
|
return textResult(await hubDelete(cfg, `${keys}/${encodeURIComponent(key_id)}`));
|
|
42921
42928
|
}
|
|
42922
42929
|
if (!name || !access) return errorResult(new Error("create_key needs a name and access (read or write)."));
|
|
42923
|
-
return textResult(await hubPost(cfg, keys, { name, access, ...kinds ? { kinds } : {} }));
|
|
42930
|
+
return textResult(await hubPost(cfg, keys, { name, access, ...kinds ? { kinds } : {}, ...n8n_credential === void 0 ? {} : { n8n_credential } }));
|
|
42924
42931
|
}
|
|
42925
42932
|
const fields = Object.fromEntries(Object.entries({ name, allowed_origins, sign_up, default_role }).filter(([, v]) => v !== void 0));
|
|
42926
42933
|
if (action === "create") return textResult(await hubPost(cfg, "/api/my-crm/v1/apps", fields));
|
|
@@ -43003,7 +43010,7 @@ server.registerTool(
|
|
|
43003
43010
|
"awesomate_crm_hooks",
|
|
43004
43011
|
{
|
|
43005
43012
|
annotations: annotate("awesomate_crm_hooks", MUTATING),
|
|
43006
|
-
description: "Send changes to an app's records to the account's own n8n: when a record of a named kind is created, updated or archived, the hub POSTs an event to a Webhook node on THEIR n8n (no other host is accepted), in order, at least once, retrying while n8n is down. Every writer counts: the app's people, its server key, Claude, a recipe, the assistant. Use it for 'when a job is requested, draft a quote', then write the result back with an app server key (awesomate_crm_apps create_key) from the same workflow. Event body: {id (stable: drop repeats), event: created|updated|archived, kind, record_id, changed: [attributes and links that changed], by, at, record (the record as it is when sent; null once archived), app}. Pro and above to change; reading is every plan. action 'list' {app_id}: each hook with delivered/missed counts and its last error. 'create' {app_id, name, url, kinds, events?}: url is the PRODUCTION webhook URL of an active workflow on their n8n (create and activate the workflow first with the awesomate_n8n tools);
|
|
43013
|
+
description: "Send changes to an app's records to the account's own n8n: when a record of a named kind is created, updated or archived, the hub POSTs an event to a Webhook node on THEIR n8n (no other host is accepted), in order, at least once, retrying while n8n is down. Every writer counts: the app's people, its server key, Claude, a recipe, the assistant. Use it for 'when a job is requested, draft a quote', then write the result back with an app server key (awesomate_crm_apps create_key) from the same workflow. Event body: {id (stable: drop repeats), event: created|updated|archived, kind, record_id, changed: [attributes and links that changed], by, at, record (the record as it is when sent; null once archived), app}. Pro and above to change; reading is every plan. action 'list' {app_id}: each hook with delivered/missed counts and its last error. 'create' {app_id, name, url, kinds, events?}: url is the PRODUCTION webhook URL of an active workflow on their n8n (create and activate the workflow first with the awesomate_n8n tools); pass n8n_credential: true (prefer it) and the hub puts the secret straight into an n8n Header Auth credential named 'Awesomate hook: <name>' on their n8n and returns only its id and name, so nothing secret passes through you: set the Webhook node's Authentication to Header Auth and pick that credential. Without it the secret comes back ONCE: put it into an n8n Header Auth credential (header X-Awesomate-Webhook-Secret), never into a reply. Removing the hook removes a credential the hub made. A new hook starts from now. 'update' {app_id, hook_id, name?, url?, kinds?, events?, enabled?}: enabled true retries at once. 'remove' {app_id, hook_id}. 'test' {app_id, hook_id}: one test event now ({event: 'test'}), and what n8n answered. Confirm the kinds and what the workflow will do with the user before creating one.",
|
|
43007
43014
|
inputSchema: {
|
|
43008
43015
|
action: external_exports.enum(["list", "create", "update", "remove", "test"]),
|
|
43009
43016
|
app_id: external_exports.string().max(48).describe("the app, from awesomate_crm_apps list"),
|
|
@@ -43012,16 +43019,17 @@ server.registerTool(
|
|
|
43012
43019
|
url: external_exports.string().max(500).optional().describe("create/update: the production URL of a Webhook node on the account's own n8n"),
|
|
43013
43020
|
kinds: external_exports.array(external_exports.string().max(41)).max(20).optional(),
|
|
43014
43021
|
events: external_exports.array(external_exports.enum(["created", "updated", "archived"])).max(3).optional().describe("default all three"),
|
|
43015
|
-
enabled: external_exports.boolean().optional().describe("update only")
|
|
43022
|
+
enabled: external_exports.boolean().optional().describe("update only"),
|
|
43023
|
+
n8n_credential: external_exports.boolean().optional().describe("create: put the secret into an n8n credential instead of the answer (recommended)")
|
|
43016
43024
|
}
|
|
43017
43025
|
},
|
|
43018
|
-
async ({ action, app_id, hook_id, name, url, kinds, events, enabled }) => {
|
|
43026
|
+
async ({ action, app_id, hook_id, name, url, kinds, events, enabled, n8n_credential }) => {
|
|
43019
43027
|
try {
|
|
43020
43028
|
const cfg = requireConfig();
|
|
43021
43029
|
const path = `/api/my-crm/v1/apps/${encodeURIComponent(app_id)}/hooks`;
|
|
43022
43030
|
if (action === "list") return textResult(await hubGet(cfg, path));
|
|
43023
43031
|
const fields = Object.fromEntries(Object.entries({ name, url, kinds, events }).filter(([, v]) => v !== void 0));
|
|
43024
|
-
if (action === "create") return textResult(await hubPost(cfg, path, fields));
|
|
43032
|
+
if (action === "create") return textResult(await hubPost(cfg, path, { ...fields, ...n8n_credential === void 0 ? {} : { n8n_credential } }));
|
|
43025
43033
|
if (!hook_id) return errorResult(new Error(`${action} needs hook_id, from list.`));
|
|
43026
43034
|
const one = `${path}/${encodeURIComponent(hook_id)}`;
|
|
43027
43035
|
if (action === "remove") return textResult(await hubDelete(cfg, one));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@awesomate/hosting-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.53.0",
|
|
4
4
|
"description": "Awesomate MCP server — lets Claude manage your Awesomate WordPress hosting, plan, limits, n8n automations, and build Node/static apps + databases",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
package/skill/CHANGELOG.json
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"versions": [
|
|
3
|
+
{
|
|
4
|
+
"version": "0.53.0",
|
|
5
|
+
"highlights": [
|
|
6
|
+
"Fields only your team sees: mark an attribute visible to staff only (awesomate_crm_kinds, set_visibility), such as the cost behind a quote or an internal note on a job. Customers signed in to your portal read it as empty and cannot change it",
|
|
7
|
+
"Your own database enforces it, not the portal's code, and Bree, answering as the customer, never sees it either. You and Claude always see every field"
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"version": "0.52.0",
|
|
12
|
+
"highlights": [
|
|
13
|
+
"When your n8n is the one receiving, Claude can ask the hub to put a record hook's secret or an app server key straight into an n8n credential on your instance (n8n_credential). Nobody sees the secret, not Claude and not you",
|
|
14
|
+
"Removing the hook or revoking the key removes that credential too, so n8n never offers a dead one"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
3
17
|
{
|
|
4
18
|
"version": "0.51.0",
|
|
5
19
|
"highlights": [
|
|
@@ -44,8 +44,13 @@ Ask, one or two at a time:
|
|
|
44
44
|
|
|
45
45
|
- **Link the thing to the customer's contact.** That link is what "their own" means.
|
|
46
46
|
- Mark an attribute `readable_by_ai` only when the owner wants Claude and AI assistants to see
|
|
47
|
-
it. Never for anything sensitive.
|
|
48
|
-
|
|
47
|
+
it. Never for anything sensitive. `readable_by_ai` is only about AI.
|
|
48
|
+
- **Fields only the team sees** (a cost, an internal note): give the attribute
|
|
49
|
+
`visible_to: ['staff']` when defining it, or later with `awesomate_crm_kinds
|
|
50
|
+
{action:'set_visibility'}`. Customers read it as null and cannot write it; the database
|
|
51
|
+
enforces it, and so does what the assistant sees. Without `visible_to`, everyone who can read
|
|
52
|
+
the record sees the attribute. Don't make such an attribute `required` on a kind customers
|
|
53
|
+
create, or they cannot create one.
|
|
49
54
|
- Show the owner the design ("A job has a title, a status and a quote, and belongs to a
|
|
50
55
|
customer. Messages hang off a job.") and get a yes first.
|
|
51
56
|
|
|
@@ -133,12 +138,14 @@ name and the default mode with the owner: switching it on lets an AI reply to th
|
|
|
133
138
|
## 7. Optional: automation
|
|
134
139
|
|
|
135
140
|
- **Server key** (`awesomate_crm_apps {action:'create_key'}`): for the app's own server or an n8n
|
|
136
|
-
workflow to read and write records. Read or write, only the kinds it needs.
|
|
137
|
-
|
|
141
|
+
workflow to read and write records. Read or write, only the kinds it needs. For n8n pass
|
|
142
|
+
`n8n_credential: true`: the hub puts the key into a credential on their n8n and you never see
|
|
143
|
+
it. Otherwise it is shown once: straight into the server's environment, never a reply or a repo.
|
|
138
144
|
- **Record events** (`awesomate_crm_hooks`): when a record of a kind is created, updated or
|
|
139
145
|
archived, the account's own n8n gets an event at once. Build and activate the workflow first
|
|
140
|
-
(awesomate-n8n skill), then create the hook with its production webhook URL and
|
|
141
|
-
|
|
146
|
+
(awesomate-n8n skill), then create the hook with its production webhook URL and
|
|
147
|
+
`n8n_credential: true`, and pick the credential it names in the Webhook node (Header Auth).
|
|
148
|
+
Use `test` to check it. Example: a job is
|
|
142
149
|
requested, the workflow drafts a quote and writes it back with a write key for `job`.
|
|
143
150
|
|
|
144
151
|
## 8. Check it works
|