Code-Native Endpoint Configuration
By default, instances of integrations that you deploy will be assigned unique webhook URLs - one URL for each flow. We call this Instance and Flow Specific endpoint configuration. Alternatively, you can choose Instance Specific endpoint configuration (each instance gets its own webhook URL and all flows share the single URL) or Shared endpoint configuration, where all flows of all instances share one URL.
To specify endpoint type, add an endpointType
property to the integration()
definition in src/index.ts
.
It can have values "instance_specific"
, "flow_specific"
or "shared_instance"
, and defaults to "flow_specific"
:
import { integration } from "@prismatic-io/spectral";
import flows from "./flows";
import { configPages } from "./configPages";
export default integration({
name: "shared-endpoint-example",
description: "Shared Endpoint Example",
iconPath: "icon.png",
flows,
configPages,
componentRegistry,
endpointType: "instance_specific",
});
When Instance Specific or Shared endpoint configuration is selected, you need some logic to determine which flow (and which customer's instance in the case of Shared) should be run. This can be done with or without a preprocess flow, and both methods are described below.
Full documentation on endpoint configuration is available in the Endpoint Configuration article.
Endpoint configuration in code-native without preprocess flow
If the flow that you want to run is specified in the webhook request's body or in a header, you can configure shared endpoint without a preprocess flow.
If, for example, the flow you want to run is specified using a header named x-acme-flow
, note that header's name in your integration definition using the triggerPreprocessFlowConfig
property:
export default integration({
name: "shared-endpoint-example",
description: "Shared Endpoint Example",
iconPath: "icon.png",
flows,
configPages,
componentRegistry,
endpointType: "instance_specific",
triggerPreprocessFlowConfig: {
flowNameField: "headers.x-acme-flow",
},
});
To invoke an instance of an execution that has been deployed, this curl
command would invoke the flow named "Create Opportunity":
curl https://hooks.prismatic.io/trigger/SW5ExampleInstanceSpecificEndpoint \
-X POST \
--header "content-type: application/json" \
--header "x-acme-flow: Create Opportunity" \
--data '{
"opportunity": {
"name": "Foo",
"amount": 10000
}
}'
If all of your instances share an endpoint, you can similarly specify a customer external ID from the request body or headers:
export default integration({
name: "shared-endpoint-example",
description: "Shared Endpoint Example",
iconPath: "icon.png",
flows,
configPages,
componentRegistry,
endpointType: "shared_instance",
triggerPreprocessFlowConfig: {
flowNameField: "headers.x-acme-flow",
externalCustomerIdField: "body.data.acmeAccountId",
},
});
curl https://hooks.prismatic.io/trigger/SW5ExampleSharedEndpoint \
-X POST \
--header "content-type: application/json" \
--header "x-acme-flow: Create Opportunity" \
--data '{
"acmeAccountId": "abc-123",
"opportunity": {
"name": "Foo",
"amount": 10000
}
}'
Endpoint configuration in code-native with preprocess flow
A preprocess flow allows you to run custom logic to determine which flow should be run (and in the case of Shared endpoint config, which customer should be run). One of your flows can look at the request body or headers, make API calls, etc., and then return the name of the flow (and customer) to run.
If you use a preprocess flow, one (and exactly one) of your flows must be marked as the preprocess flow.
You cannot specify both a preprocess flow and a triggerPreprocessFlowConfig
property.
This example preprocess flow has an onExecution
function (like any other flow).
This flow returns two properties: myFlowName
and myCustomerId
- you can name those properties whatever you like.
These property preprocessFlowConfig
specifies which properties to look for in the response from the preprocess flow:
import axios from "axios";
import { flow } from "@prismatic-io/spectral";
const flowMapper = {
create_opportunity: "Create Opportunity",
update_opportunity: "Update Opportunity",
};
interface CreateOpportunityPayload {
event: "create_opportunity";
acctId: string;
opportunity: {
name: string;
amount: number;
};
}
interface UpdateOpportunityPayload {
event: "update_opportunity";
acctId: string;
opportunity: {
id: string;
name: string;
amount: number;
};
}
type Payload = CreateOpportunityPayload | UpdateOpportunityPayload;
export const myPreprocessFlow = flow({
name: "My Preprocess Flow",
stableKey: "my-preprocess-flow",
preprocessFlowConfig: {
flowNameField: "myFlowName",
externalCustomerIdField: "myCustomerId",
},
description: "This determines which sibling flow should be invoked",
onExecution: async (context, params) => {
const { event, acctId } = params.onTrigger.results.body.data as Payload;
const customerIdResponse = await axios.post(
"https://api.example.com/get-customer-id",
{
acmeAcctId: acctId,
},
);
return Promise.resolve({
data: {
myFlowName: flowMapper[event],
myCustomerId: customerIdResponse.data.customerId,
},
});
},
});
The above preprocess flow will look at a property named event
in the request body and map an event of create_opportunity
to the string Create Opportunity
, returning Create Opportunity
as the name of the flow to run.
It will also extract an acctId
from the request body and make an HTTP request to https://api.example.com/get-customer-id
to get an external customer ID, returning that customer ID as well.
curl https://hooks.prismatic.io/trigger/SW5ExampleSharedEndpoint \
-X POST \
--header "content-type: application/json" \
--data '{
"event": "create_opportunity",
"acctId": "abc-123",
"opportunity": {
"name": "Foo",
"amount": 10000
}
}'
To create a preprocess flow for Instance Specific endpoint configuration, omit the externalCustomerIdField
property from the preprocessFlowConfig
object.