Environments
Compare resources between environments
Compares workflows and other resources between the source and target environments, returning detailed diff information including additions, modifications, and deletions.
POST
/
v2
/
environments
/
{targetEnvironmentId}
/
diff
TypeScript
import { Novu } from "@novu/api";
const novu = new Novu({
secretKey: "YOUR_SECRET_KEY_HERE",
});
async function run() {
const result = await novu.environments.diff({
sourceEnvironmentId: "507f1f77bcf86cd799439011",
}, "6615943e7ace93b0540ae377");
console.log(result);
}
run();using Novu;
using Novu.Models.Components;
var sdk = new NovuSDK(secretKey: "YOUR_SECRET_KEY_HERE");
var res = await sdk.Environments.DiffAsync(
targetEnvironmentId: "6615943e7ace93b0540ae377",
diffEnvironmentRequestDto: new DiffEnvironmentRequestDto() {
SourceEnvironmentId = "507f1f77bcf86cd799439011",
}
);
// handle responsedeclare(strict_types=1);
require 'vendor/autoload.php';
use novu;
use novu\Models\Components;
$sdk = novu\Novu::builder()
->setSecurity(
'YOUR_SECRET_KEY_HERE'
)
->build();
$diffEnvironmentRequestDto = new Components\DiffEnvironmentRequestDto(
sourceEnvironmentId: '507f1f77bcf86cd799439011',
);
$response = $sdk->environments->diff(
targetEnvironmentId: '6615943e7ace93b0540ae377',
diffEnvironmentRequestDto: $diffEnvironmentRequestDto
);
if ($response->diffEnvironmentResponseDto !== null) {
// handle response
}from novu_py import Novu
with Novu(
secret_key="YOUR_SECRET_KEY_HERE",
) as novu:
res = novu.environments.diff(target_environment_id="6615943e7ace93b0540ae377", diff_environment_request_dto={
"source_environment_id": "507f1f77bcf86cd799439011",
})
# Handle response
print(res)package main
import(
"context"
"github.com/novuhq/novu-go/v3"
"github.com/novuhq/novu-go/v3/models/components"
"log"
)
func main() {
ctx := context.Background()
s := v3.New(
v3.WithSecurity("YOUR_SECRET_KEY_HERE"),
)
res, err := s.Environments.Diff(ctx, "6615943e7ace93b0540ae377", components.DiffEnvironmentRequestDto{
SourceEnvironmentID: v3.Pointer("507f1f77bcf86cd799439011"),
}, nil)
if err != nil {
log.Fatal(err)
}
if res.DiffEnvironmentResponseDto != nil {
// handle response
}
}curl --request POST \
--url https://api.novu.co/v2/environments/{targetEnvironmentId}/diff \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"sourceEnvironmentId": "507f1f77bcf86cd799439011"
}
'const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({sourceEnvironmentId: '507f1f77bcf86cd799439011'})
};
fetch('https://api.novu.co/v2/environments/{targetEnvironmentId}/diff', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));HttpResponse<String> response = Unirest.post("https://api.novu.co/v2/environments/{targetEnvironmentId}/diff")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"sourceEnvironmentId\": \"507f1f77bcf86cd799439011\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.novu.co/v2/environments/{targetEnvironmentId}/diff")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"sourceEnvironmentId\": \"507f1f77bcf86cd799439011\"\n}"
response = http.request(request)
puts response.read_body{
"sourceEnvironmentId": "<string>",
"targetEnvironmentId": "<string>",
"resources": [
{
"changes": [
{
"sourceResource": {
"id": "<string>",
"name": "<string>",
"updatedBy": {
"_id": "<string>",
"firstName": "<string>",
"lastName": "<string>",
"externalId": "<string>"
},
"updatedAt": "2024-01-15T10:30:00.000Z"
},
"targetResource": {
"id": "<string>",
"name": "<string>",
"updatedBy": {
"_id": "<string>",
"firstName": "<string>",
"lastName": "<string>",
"externalId": "<string>"
},
"updatedAt": "2024-01-15T10:30:00.000Z"
},
"diffs": {
"previous": {},
"new": {}
},
"stepType": "<string>",
"previousIndex": 123,
"newIndex": 123
}
],
"summary": {
"added": 123,
"modified": 123,
"deleted": 123,
"unchanged": 123
},
"sourceResource": {
"id": "<string>",
"name": "<string>",
"updatedBy": {
"_id": "<string>",
"firstName": "<string>",
"lastName": "<string>",
"externalId": "<string>"
},
"updatedAt": "2024-01-15T10:30:00.000Z"
},
"targetResource": {
"id": "<string>",
"name": "<string>",
"updatedBy": {
"_id": "<string>",
"firstName": "<string>",
"lastName": "<string>",
"externalId": "<string>"
},
"updatedAt": "2024-01-15T10:30:00.000Z"
},
"dependencies": [
{
"resourceId": "<string>",
"resourceName": "<string>",
"isBlocking": true
}
]
}
],
"summary": {
"totalEntities": 123,
"totalChanges": 123,
"hasChanges": true
}
}{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"errors": {
"fieldName1": {
"messages": [
"Field is required",
"Must be a valid email address"
],
"value": "invalidEmail"
},
"fieldName2": {
"messages": [
"Must be at least 18 years old"
],
"value": 17
},
"fieldName3": {
"messages": [
"Must be a boolean value"
],
"value": true
},
"fieldName4": {
"messages": [
"Must be a valid object"
],
"value": {
"key": "value"
}
},
"fieldName5": {
"messages": [
"Field is missing"
],
"value": null
},
"fieldName6": {
"messages": [
"Undefined value"
]
}
},
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}"API rate limit exceeded"{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}"Please wait some time, then try again."Authorizations
API key authentication. Allowed headers-- "Authorization: ApiKey <novu_secret_key>".
Headers
A header for idempotency purposes
Path Parameters
Target environment ID (MongoDB ObjectId) to compare against
Body
application/json
Diff request configuration
Source environment ID to compare from. Defaults to the Development environment if not provided.
Example:
"507f1f77bcf86cd799439011"
Was this page helpful?
⌘I
TypeScript
import { Novu } from "@novu/api";
const novu = new Novu({
secretKey: "YOUR_SECRET_KEY_HERE",
});
async function run() {
const result = await novu.environments.diff({
sourceEnvironmentId: "507f1f77bcf86cd799439011",
}, "6615943e7ace93b0540ae377");
console.log(result);
}
run();using Novu;
using Novu.Models.Components;
var sdk = new NovuSDK(secretKey: "YOUR_SECRET_KEY_HERE");
var res = await sdk.Environments.DiffAsync(
targetEnvironmentId: "6615943e7ace93b0540ae377",
diffEnvironmentRequestDto: new DiffEnvironmentRequestDto() {
SourceEnvironmentId = "507f1f77bcf86cd799439011",
}
);
// handle responsedeclare(strict_types=1);
require 'vendor/autoload.php';
use novu;
use novu\Models\Components;
$sdk = novu\Novu::builder()
->setSecurity(
'YOUR_SECRET_KEY_HERE'
)
->build();
$diffEnvironmentRequestDto = new Components\DiffEnvironmentRequestDto(
sourceEnvironmentId: '507f1f77bcf86cd799439011',
);
$response = $sdk->environments->diff(
targetEnvironmentId: '6615943e7ace93b0540ae377',
diffEnvironmentRequestDto: $diffEnvironmentRequestDto
);
if ($response->diffEnvironmentResponseDto !== null) {
// handle response
}from novu_py import Novu
with Novu(
secret_key="YOUR_SECRET_KEY_HERE",
) as novu:
res = novu.environments.diff(target_environment_id="6615943e7ace93b0540ae377", diff_environment_request_dto={
"source_environment_id": "507f1f77bcf86cd799439011",
})
# Handle response
print(res)package main
import(
"context"
"github.com/novuhq/novu-go/v3"
"github.com/novuhq/novu-go/v3/models/components"
"log"
)
func main() {
ctx := context.Background()
s := v3.New(
v3.WithSecurity("YOUR_SECRET_KEY_HERE"),
)
res, err := s.Environments.Diff(ctx, "6615943e7ace93b0540ae377", components.DiffEnvironmentRequestDto{
SourceEnvironmentID: v3.Pointer("507f1f77bcf86cd799439011"),
}, nil)
if err != nil {
log.Fatal(err)
}
if res.DiffEnvironmentResponseDto != nil {
// handle response
}
}curl --request POST \
--url https://api.novu.co/v2/environments/{targetEnvironmentId}/diff \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"sourceEnvironmentId": "507f1f77bcf86cd799439011"
}
'const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({sourceEnvironmentId: '507f1f77bcf86cd799439011'})
};
fetch('https://api.novu.co/v2/environments/{targetEnvironmentId}/diff', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));HttpResponse<String> response = Unirest.post("https://api.novu.co/v2/environments/{targetEnvironmentId}/diff")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"sourceEnvironmentId\": \"507f1f77bcf86cd799439011\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.novu.co/v2/environments/{targetEnvironmentId}/diff")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"sourceEnvironmentId\": \"507f1f77bcf86cd799439011\"\n}"
response = http.request(request)
puts response.read_body{
"sourceEnvironmentId": "<string>",
"targetEnvironmentId": "<string>",
"resources": [
{
"changes": [
{
"sourceResource": {
"id": "<string>",
"name": "<string>",
"updatedBy": {
"_id": "<string>",
"firstName": "<string>",
"lastName": "<string>",
"externalId": "<string>"
},
"updatedAt": "2024-01-15T10:30:00.000Z"
},
"targetResource": {
"id": "<string>",
"name": "<string>",
"updatedBy": {
"_id": "<string>",
"firstName": "<string>",
"lastName": "<string>",
"externalId": "<string>"
},
"updatedAt": "2024-01-15T10:30:00.000Z"
},
"diffs": {
"previous": {},
"new": {}
},
"stepType": "<string>",
"previousIndex": 123,
"newIndex": 123
}
],
"summary": {
"added": 123,
"modified": 123,
"deleted": 123,
"unchanged": 123
},
"sourceResource": {
"id": "<string>",
"name": "<string>",
"updatedBy": {
"_id": "<string>",
"firstName": "<string>",
"lastName": "<string>",
"externalId": "<string>"
},
"updatedAt": "2024-01-15T10:30:00.000Z"
},
"targetResource": {
"id": "<string>",
"name": "<string>",
"updatedBy": {
"_id": "<string>",
"firstName": "<string>",
"lastName": "<string>",
"externalId": "<string>"
},
"updatedAt": "2024-01-15T10:30:00.000Z"
},
"dependencies": [
{
"resourceId": "<string>",
"resourceName": "<string>",
"isBlocking": true
}
]
}
],
"summary": {
"totalEntities": 123,
"totalChanges": 123,
"hasChanges": true
}
}{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"errors": {
"fieldName1": {
"messages": [
"Field is required",
"Must be a valid email address"
],
"value": "invalidEmail"
},
"fieldName2": {
"messages": [
"Must be at least 18 years old"
],
"value": 17
},
"fieldName3": {
"messages": [
"Must be a boolean value"
],
"value": true
},
"fieldName4": {
"messages": [
"Must be a valid object"
],
"value": {
"key": "value"
}
},
"fieldName5": {
"messages": [
"Field is missing"
],
"value": null
},
"fieldName6": {
"messages": [
"Undefined value"
]
}
},
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}"API rate limit exceeded"{
"statusCode": 404,
"timestamp": "2024-12-12T13:00:00Z",
"path": "/api/v1/resource",
"message": "xx xx xx ",
"ctx": {
"workflowId": "some_wf_id",
"stepId": "some_wf_id"
},
"errorId": "abc123"
}"Please wait some time, then try again."