Set up backend
The automation's backend is the logic that you want to execute when a trigger event occurs. It will run on all entities tied to the blueprint specified in the automation's definition, whenever the trigger event occurs.
Port uses the same backend types for automations and for self-service actions.
Define the backend
The automation's backend is defined under the Backend
tab of the automation creation form in Port's UI.
Let's break the definition down to two parts:
Define your backend's type and metadata
In this section we provide information about the backend logic and its location, so that Port can access and run it.
Port uses the same backend types for both automations and self-service actions.
For more information and examples for the available backend types, check out the backend types page.
Depending on the backend type you choose, you will need to provide different configuration parameters.
Define the payload
When creating an automation, you can construct a JSON payload that will be sent to your backend upon every execution. You can use this to send data about the automation that you want your backend to have.
Still in the Backend
tab, scroll down to the Configure the invocation payload
section. This is where we define the automation's payload.
The payload is defined using JSON, and accessing your data is done using jq
, wrapping each expression with {{ }}
.
Here is an example for an automation payload:
{
"port_context": {
"runId": "{{ .run.id }}"
}
}
You may have noticed that the example above also sends {{ .run.id }}
. This is a unique identifier for each execution of the automation, and can be used to interact with the autmation run in Port from your backend.
Now you might be thinking - how do I know what data is available to me when constructing the payload?
Enter trigger data
.
Trigger data
When a self-service action or automation is executed, Port creates an object that contains data about the execution.
This entire object is accessible to you when constructing the payload.
Depending on the trigger type, the object's structure will differ:
- Entity trigger
- Action run trigger
Below is an example of trigger data for an automation that triggers whenever a service
entity is updated:
{
"inputs": null,
"trigger": {
"by": {
"orgId": "org_BneDtWovPqXaA2VZ",
"userId": "auth0|62ceaea697ca00f09d7c4f45",
"user": {
"email": "example-user@test.com",
"firstName": "SomeFirstName",
"lastName": "SomeLastName",
"phoneNumber": "",
"picture": "",
"providers": [],
"status": "ACTIVE",
"id": "auth0|62ceaea697ca00f09d7c4f45",
"createdAt": "2024-06-09T09:57:50.444Z",
"updatedAt": "2024-06-09T09:57:50.444Z"
}
},
"origin": "AUTOMATION",
"at": "2024-06-09T12:28:18.663Z"
},
"event": {
"action": "UPDATE",
"resourceType": "entity",
"trigger": {
"by": {
"orgId": "org_BneDtWovPqXaA2VZ",
"userId": "auth0|62ceaea697ca00f09d7c4f45"
},
"origin": "UI",
"at": "2024-06-09T12:28:18.477Z"
},
"context": {
"blueprintIdentifier": "service",
"entityIdentifier": "example-service-identifier",
"propertyIdentifier": null
},
"diff": {
"before": {
"identifier": "example-service-identifier",
"title": "Example service",
"icon": null,
"blueprint": "service",
"team": [
"Rocket"
],
"properties": {
"latestVersion": "12.8.2",
"language": "TypeScript",
"one_hop_service_language": "Ruby",
"two_hops_service_language": "Ruby",
"repo": "https://github.com/some-org/example-service"
},
"relations": {
"using": "rogue-service"
},
"createdAt": "2024-06-09T09:57:52.931Z",
"createdBy": "60EsooJtOqimlekxrNh7nfr2iOgTcyLZ",
"updatedAt": "2024-06-09T09:57:52.931Z",
"updatedBy": "60EsooJtOqimlekxrNh7nfr2iOgTcyLZ"
},
"after": {
"identifier": "example-service-identifier",
"title": "Example service renamed",
"icon": "Microservice",
"blueprint": "service",
"team": [
"Rocket"
],
"properties": {
"latestVersion": "12.8.22",
"language": "Python",
"one_hop_service_language": "Ruby",
"two_hops_service_language": "Ruby",
"repo": "https://github.com/some-org/example-service"
},
"relations": {
"using": "rogue-service"
},
"createdAt": "2024-06-09T09:57:52.931Z",
"createdBy": "60EsooJtOqimlekxrNh7nfr2iOgTcyLZ",
"updatedAt": "2024-06-09T12:28:18.628Z",
"updatedBy": "auth0|62ceaea697ca00f09d7c4f45"
}
}
},
"entity": null,
"action": {
"identifier": "automation"
},
"run": {
"id": "r_k86OUzq80jRlxFV0"
}
}
The example above is for an automation that uses the ENTITY_UPDATED
trigger event. The event.diff
object contains data from before
and after
the update.
The other trigger events have the same structure, with the following differences:
-
ENTITY_CREATED
- In thediff
object,before
will benull
, andafter
will contain the new entity data. -
ENTITY_DELETED
- In thediff
object,before
will contain the entity data before deletion, andafter
will benull
. -
ANY_ENTITY_CHANGE
- Thediff
object will containbefore
and/orafter
data according to the entity change. -
TIMER_PROPERTY_EXPIRED
- In thediff
object, there will be anafter
object containing the entity data.
Below is an example of trigger data for an automation that triggers whenever an action run is updated:
{
"inputs": null,
"trigger": {
"by": {
"orgId": "org_BneDtWovPqXaA2VZ",
"userId": "auth0|62ceaaa497ea00f09d7c4f41",
"user": {
"email": "test-admin-user@test.com",
"firstName": "James",
"lastName": "Hetfield",
"status": "ACTIVE",
"id": "auth0|82zea497e300f09d7c1f41",
"createdAt": "2024-08-15T11:17:02.699Z",
"updatedAt": "2024-08-15T11:17:02.699Z"
}
},
"origin": "AUTOMATION",
"at": "2024-08-15T12:30:05.569Z"
},
"event": {
"id": "event_GH2680QIOEzwwNZB",
"resourceType": "run",
"action": "UPDATE",
"trigger": {
"by": {
"orgId": "org_BneVtWovPbXaA6V6Z",
"userId": "auth0|82zea497e300f09d7c1f41"
},
"origin": "UI",
"at": "2024-08-15T12:30:05.505Z"
},
"context": {
"action": {
"identifier": "myActionId",
"title": "Some action title",
"trigger": {
"type": "self-service",
"operation": "CREATE",
"userInputs": {
"properties": {},
"required": [],
"order": []
}
},
"invocationMethod": {
"type": "WEBHOOK",
"url": "https://example.com",
"agent": false,
"synchronized": false,
"method": "POST",
"headers": {
"RUN_ID": "{{ .run.id }}"
},
"body": {
"{{ spreadValue() }}": "{{ .inputs }}",
"port_context": {
"runId": "{{ .run.id }}"
}
}
},
"requiredApproval": false,
"createdBy": "auth0|82zea497e300f09d7c1f41",
"updatedBy": "auth0|82zea497e300f09d7c1f41",
"createdAt": "2024-08-15T12:29:45.817Z",
"updatedAt": "2024-08-15T12:29:45.817Z"
}
},
"diff": {
"before": {
"id": "r_Q0YotCZMKxDLdlaU",
"status": "IN_PROGRESS",
// "blueprint" and "entity" will be available if the action is tied to a blueprint
// (meaning that the action run is tied to an entity)
"blueprint": {
"identifier": "blueprintIdentifier",
"title": "blueprintTitle",
"icon": "blueprintIcon"
},
"entity": {
"identifier": "entityIdentifier",
"title": "entityTitle",
"icon": "entityIcon",
},
"action": {
"identifier": "myActionId",
"title": null,
"icon": null,
"deleted": true
},
"source": "UI",
"link": [],
"requiredApproval": false,
"properties": {},
"createdAt": "2024-08-15T12:29:57.379Z",
"updatedAt": "2024-08-15T12:29:57.379Z",
"createdBy": "auth0|82zea497e300f09d7c1f41",
"updatedBy": "auth0|82zea497e300f09d7c1f41",
"payload": {
"type": "WEBHOOK",
"url": "https://example.com",
"agent": false,
"synchronized": false,
"method": "POST",
"headers": {
"RUN_ID": "r_Q0YotCZMKxDLdlaU"
},
"body": {
"port_context": {
"runId": "r_Q0YotCZMKxDLdlaU"
}
}
}
},
"after": {
"id": "r_Q0YotCZMKxDLdlaU",
"status": "IN_PROGRESS",
// "blueprint" and "entity" will be available if the action is tied to a blueprint
// (meaning that the action run is tied to an entity)
"blueprint": {
"identifier": "blueprintIdentifier",
"title": "blueprintTitle",
"icon": "blueprintIcon"
},
"entity": {
"identifier": "entityIdentifier",
"title": "entityTitle",
"icon": "entityIcon",
},
"action": {
"identifier": "myActionId",
"title": null,
"icon": null,
"deleted": true
},
"source": "UI",
"link": [],
"requiredApproval": false,
"properties": {},
"createdAt": "2024-08-15T12:29:57.379Z",
"updatedAt": "2024-08-15T12:30:05.481Z",
"createdBy": "auth0|82zea497e300f09d7c1f41",
"updatedBy": "auth0|82zea497e300f09d7c1f41",
"payload": {
"type": "WEBHOOK",
"url": "https://example.com",
"agent": false,
"synchronized": false,
"method": "POST",
"headers": {
"RUN_ID": "r_Q0YotCZMKxDLdlaU"
},
"body": {
"port_context": {
"runId": "r_Q0YotCZMKxDLdlaU"
}
}
}
}
}
},
"entity": null,
"action": {
"identifier": "automation"
},
"run": {
"id": "r_au3aJdlOHUO3d99n"
}
}
The example above is for an automation that uses the RUN_UPDATED
trigger event. The event.diff
object contains data from before
and after
the update.
The other trigger events have the same structure, with the following differences:
-
RUN_CREATED
- In thediff
object,before
will benull
, andafter
will contain the new action run data. -
ANY_RUN_CHANGE
- Thediff
object will containbefore
and/orafter
data according to the entity change.
You can access any value in this structure and add it to the payload. For example, to add the executing user's name to the payload, you can use the following expression:
{
"executing_user_email": "{{.trigger.by.user.email}}"
}
Use the Test JQ
button in the bottom-left corner to test your expressions against your automation and ensure you are sending the correct data.
jq
You can use the jq
expression {{ . }}
when testing to see the entire available object, and then drill down to the specific data you need.
Using secrets in the payload
Sensitive data such as tokens and passwords can be stored using Port secrets.
To use a secret in the payload, you can reference it using {{ .secrets.<secret_name> }}
.
For example:
"token": "{{ .secrets.token_name }}"
spreadValue() function
You can use the spreadValue()
function to add multiple keys to the root of the payload at once. This function will spread all of the keys under a given object.
A common use case for this function is to add all of the user inputs to the payload:
{
"{{ spreadValue() }}": "{{ .inputs }}"
}
This will add all of the action's/automation's user inputs to the root of the payload, so that they can be accessed directly by your backend.
Using jq
expressions in keys
The keys in the payload can also be jq
expressions.
For example, the following expression will add the ref
key to the payload only if a ref
input was provided when executing the action/automation:
{
"{{if (.inputs | has(\"ref\")) then \"ref\" else null end}}": "{{.inputs.ref}}"
}
Note that if a key in the payload evaluates to null
for any reason, the entire expression (key + value) will be omitted from the payload.
Backend JSON structure
In some cases, you may prefer to define the backend configuration using a JSON object.
The backend is defined under the invocationMethod
object in the automation's JSON structure.
{
"identifier": "unique_id",
"title": "Title",
"icon": "icon_identifier",
"description": "automation description",
"trigger": {
"type": "automation",
"event": {
"type": "event_type",
"blueprintIdentifier": "blueprint_id"
},
"condition": {
"type": "JQ",
"expressions": ["expression1", "expression2"],
"combinator": "and"
}
},
"invocationMethod": {
"type": "WEBHOOK",
"url": "https://example.com",
"headers": {
"RUN_ID": "{{ .run.id }}"
},
"body": {
"payload_key": "{{ some-jq-value }}"
}
},
"publish": false
}
Supported backends
The type
field defines the action's backend type, and can have one of the following values: WEBHOOK
, GITHUB
, GITLAB
, KAFKA
, UPSERT_ENTITY
.
Depending on the backend type you choose, the available fields will be different:
- Webhook
- Github
- Gitlab
- Azure DevOps
- Kafka
- Create/update entity
invocationMethod.type
should be set to WEBHOOK
.
Field | Type | Description | Example values |
---|---|---|---|
agent | boolean | Defines whether to use Port Agent for execution or not. | true or false |
url | string | Defines the webhook URL to which Port will send the action via an HTTP POST request. | https://example.com |
method | string | Defines the HTTP method to be used for the request. | POST , PUT , DELETE , PATCH |
synchronized | boolean | If true, the action will be executed synchronously. | true or false |
headers | object | An object containing the payload headers to be sent to the webhook in each execution, in "key":"value" pairs. | |
body | object | Defines the payload that will be sent to the backend upon execution of the action. An object containing "key":"value" pairs. |
invocationMethod.type
should be set to GITHUB
.
Field | Type | Description | Example values |
---|---|---|---|
org | string | The GitHub organization name. | port-labs |
repo | string | The GitHub repository name. | port-docs |
workflow | string | Defines the GitHub workflow ID to run (You can also pass the workflow file name as a string). | workflow.yml |
reportWorkflowStatus | boolean | A flag to control whether to automatically update the Port run object status (SUCCESS/FAILURE) at the end of the workflow (default: true ). | true or false |
workflowInputs | object | Defines the payload that will be sent to the backend upon execution of the action. An object containing "key":"value" pairs. |
invocationMethod.type
should be set to GITLAB
.
Field | Type | Description | Example values |
---|---|---|---|
defaultRef | string | The default ref (branch/tag name) we want the action to use. defaultRef can be overridden dynamically, by adding ref as user input. Can only be used if type is set to GITLAB . | |
projectName | string | The GitLab project name. Can only be used if type is set to GITLAB . | port |
groupName | string | The GitLab group name. Can only be used if type is set to GITLAB . | port-labs |
pipelineVariables | object | Defines the payload that will be sent to the backend upon execution of the action. An object containing "key":"value" pairs. |
invocationMethod.type
should be set to AZURE_DEVOPS
.
Field | Type | Description | Example values |
---|---|---|---|
webhook | string | The name of the webhook resource in the Azure YAML pipeline file. | |
org | string | The Azure DevOps organization in which the pipeline is located. | port-labs |
payload | object | Defines the payload that will be sent to the backend upon execution of the action. An object containing "key":"value" pairs. |
invocationMethod.type
should be set to KAFKA
.
Field | Type | Description | Example values |
---|---|---|---|
payload | object | Defines the payload that will be sent to the backend upon execution of the action. An object containing "key":"value" pairs. |
invocationMethod.type
should be set to UPSERT_ENTITY
.
Field | Type | Description | Example values |
---|---|---|---|
blueprintIdentifier | string | The identifier of the blueprint from which the entity will be created/updated. | service |
mapping | object | Defines the properties of the entity that will be created/updated. | {"name":"newEntityName"} |
To read more about each backend type, see the backend types page.