Skip to main content
Skip table of contents

What API do I use to create/update bulk assets?

1. Purpose

The /api/asset/bulk endpoint enables bulk creation or update of master data entities such as fields, stops, routes, wells, tanks, equipment, and meters in the JoynFSM system.

2. Highlights

Create or update assets such as Field, Route, Stop, Well, Tank, Equipment, and Meter in bulk or individually.

  • Supports both creation of new assets and updates to existing ones based on the provided id.

  • Allows mapping of assets to specific areas and teams.

  • Provides detailed success and error responses for processed and unprocessed items.

  • Fully secured with Cognito-based authorization.

  • Designed for seamless integration with Joyn FDG systems.

3. API EndPoint:

/api/asset/bulk

  1. Method:

POST

5. Getting Started

  1. User Pool Configuration: Ensure your tenant is configured with a valid Cognito User Pool

  2. JWT Token: Obtain a valid JWT token from Cognito authentication

6. JSON structure

JSON
{
  // === REQUIRED FIELDS ===
  "type": "string",              // Required: Asset type (see valid values below)
  "name": "string",              // Required: Asset name
  
  // === IDENTIFIER FIELDS (At least one required) ===
  "id": "string",                // Internal UUID (auto-generated if not provided)
  "xid": "string",               // External identifier (recommended)
  "fdgxid": "string",            // FDG external identifier
  
  // === BASIC PROPERTIES ===
  "isDeleted": boolean,          // Soft delete flag (default: false)
  "latitude": number,            // Geographical coordinate
  "longitude": number,           // Geographical coordinate
  "subType": "string",           // Asset subtype
  "productType": "string",       // Product classification
  "sourceSystem": "string",      // Source system identifier
  "stopId": "string",            // Associated stop ID
  "producingMethodId": "string", // Production method reference
  "tankStrappingID": "string",   // Tank strapping identifier
  "fieldId": "string",           // Field ID (auto-populated based on references)
  "correlationId": "string",     // Request tracking identifier
  
  // === CUSTOM DATA ===
  "customAttributes": {},        // Object: Custom key-value pairs
  
  // === RELATIONSHIP OBJECTS ===
  "field": {                     // Field reference
    "id": "string",
    "xid": "string",
    "name": "string"
  },
  "route": {                     // Route reference
    "id": "string", 
    "xid": "string",
    "name": "string"
  },
  "stop": {                      // Stop reference
    "id": "string",
    "xid": "string", 
    "name": "string"
  },
  "area": {                      // Area reference
    "id": "string",
    "xid": "string",
    "name": "string"
  },
  
  // === TEAM ASSIGNMENTS ===
  "teams": [
    {
      "teamId": "string",
      "resources": [
        {
          "userId": "string",
          "resourceLevel": "string",
          "isDeleted": false
        }
      ],
      "isDeleted": false
    }
  ],
  
  // === AREA DEFINITION (For area type assets) ===
  "areaType": "STATIC|DYNAMIC",  // Required for type: "area"
  "areaDefinition": {            // Required for areaType: "DYNAMIC"
    "criteria": [
      {
        "attributeName": "string",
        "values": {}             // Object: Criteria values
      }
    ]
  },
  
  // === ATTACHMENTS ===
  "attachments": [
    {
      "bucket": "string",        // S3 bucket name
      "key": "string",           // S3 object key
      "fileName": "string",      // Original filename
      "region": "string"         // AWS region
    }
  ],
  
  // === WATCHERS & CONTACTS ===
  "watcher": {                   // Single watcher reference
    "id": "string",
    "userName": "string"
  },
  "contact": {                   // Single contact reference
    "id": "string",
    "xid": "string"
  },
  "watchers": ["string"],        // Array of watcher IDs
  "contacts": ["string"]         // Array of contact IDs
}

7. Mandatory Fields

#

Field

Guidance

1

id

Unique identifier for the asset. Required for updates; optional for creating new assets.

2

name

Name of the asset

3

type

type of the asset. Supported values include:

  • field

  • route

  • stop

  • well

  • tank

  • equipment

  • meter

4

tenantId

Tenant ID associated with the asset

8. Optional Fields

#

Field

Guidance

1

areaId

Identifier for the area to which the asset belongs.

2

areaType

Specifies whether the area is STATIC or DYNAMIC.

3

teamId

Identifier for the team responsible for the asset.

4

description

A brief description of the asset.

9. Request Format

·      List of json

·      Maximum size should be less than 6 MB

10. Key Rules

Order Matters: Create parent assets (fields) before child assets (routes/stops).
References: Use xid for reliable cross-references
Validation: Each object is validated independently
Partial Success: Some assets may succeed while others fail
Upsert Logic: Existing assets are updated, new ones are created

11. Response Format

 NOTE 1: If the response data size exceeds a certain threshold, the API will not return the full data inline.

Instead, it will provide a URL to an S3 object where the full response can be downloaded.

NOTE 2: The response always includes two arrays: processedItems and unProcessedItems.

Even if the request is partially successful, both arrays will be present, and you should check both for results and errors.

NOTE 3: If the response is offloaded to S3, the inline response will not contain the processedItems and unProcessedItems arrays directly—only the download URL.
NOTE 4: The S3 URL is temporary and may expire after a short period (typically 5–15 minutes). Download the file promptly.


12. Example Request

JSON
{
  "message": "string",
  "success": true,
  "data": {
    "processedItems": [
      {
        "message": "string",
        "record": {
          "id": "string",
          "xid": "string",
          "name": "string",
          "fdgxid": "string",
          "type": "string",
          "isDeleted": true,
          "latitude": 0,
          "longitude": 0,
          "subType": "string",
          "productType": "string",
          "sourceSystem": "string",
          "stopId": "string",
          "producingMethodId": "string",
          "tankStrappingID": "string",
          "customAttributes": {},
          "teams": [
            {
              "teamId": "string",
              "resources": [
                {
                  "userId": "string",
                  "resourceLevel": "string",
                  "isDeleted": false
                }
              ],
              "isDeleted": false
            }
          ],
          "areas": [
            {
              "areaId": "string",
              "isDeleted": false
            }
          ],
          "fdgObjectId": "string",
          "routeIds": "array",
          "fdgRouteIds": [
            "string"
          ],
          "areaType": "string",
          "bulkStopGroupName": "string",
          "fieldId": "string",
          "correlationId": "string"
        }
      }
    ],
    "unProcessedItems": [
      {
        "message": "string",
        "record": {
          "id": "string",
          "xid": "string",
          "name": "string",
          "fdgxid": "string",
          "type": "string",
          "isDeleted": true,
          "latitude": 0,
          "longitude": 0,
          "subType": "string",
          "productType": "string",
          "sourceSystem": "string",
          "stopId": "string",
          "producingMethodId": "string",
          "tankStrappingID": "string",
          "customAttributes": {},
          "teams": [
            {
              "teamId": "string",
              "resources": [
                {
                  "userId": "string",
                  "resourceLevel": "string",
                  "isDeleted": false
                }
              ],
              "isDeleted": false
            }
          ],
          "areas": [
            {
              "areaId": "string",
              "isDeleted": false
            }
          ],
          "fdgObjectId": "string",
          "routeIds": "array",
          "fdgRouteIds": [
            "string"
          ],
          "areaType": "string",
          "bulkStopGroupName": "string",
          "fieldId": "string",
          "correlationId": "string"
        }
      }
    ]
  }
}

Example Request for stop

JSON
[
  {
    "attachments": [],
    "latitude": 100,
    "description": "Godric gryffindor -testing1",
    "areas": [
      {
        "areaId": "8cc5fac8-1598-4794-b7fb-8a2796d17311",
        "isDeleted": false
      },
      {
        "areaId": "78469401-fd18-497d-ae10-39cf653da070",
        "isDeleted": false
      }
    ],
    "availability": [],
    "createdBy": "shivar@sevenlakes.com",
    "createdOn": "2023-07-05T10:07:54.862Z",
    "customAttributes": {
      "C_DC_FLAG": "Yes",
      "Foreman": "harry, test"
    },
    "cxid": "Gryffindor Common Room",
    "fieldId": "5be5b1a8-eda5-42cf-b931-3a8e97c61b31",
    "id": "35391454-7152-4f87-b17b-d7175552e225",
    "longitude": 100,
    "modifiedBy": "Joynfsmscript@wenergysoftware.com",
    "modifiedOn": "2024-02-26T12:59:21.030Z",
    "name": "Gryffindor Common Room",
    "preferredLocations": {},
    "stopId": "35391454-7152-4f87-b17b-d7175552e225",
    "tenantId": "00e29a9d-6621-43a4-a6c2-a25c67939e5a",
    "type": "stop",
    "watchers": []
  }
]

Example Request for Tank

JSON
[
  {
    "name": "tank123",
    "description": "creating tank for field-BLR",
    "type": "tank",
    "attachments": [],
    "availability": [],
    "customAttributes": {},
    "field": {
      "id": "5be5b1a8-eda5-42cf-b931-3a8e97c61b31"
    },
    "preferredLocations": {},
    "stop": {
      "id": "33f9d517-56af-4c27-8ab0-13a88dcbc780"
    },
    "watchers": [
      "2f313acc-a0d9-44af-9789-32025e0cee87"
    ]
  }
]

Example request for well

JSON
[
  {
    "name": "well123",
    "description": "creatin well using field BLR",
    "type": "well",
    "attachments": [],
    "availability": [],
    "customAttributes": {},
    "field": {
      "id": "5be5b1a8-eda5-42cf-b931-3a8e97c61b31"
    },
    "preferredLocations": {},
    "stop": {
      "id": "33f9d517-56af-4c27-8ab0-13a88dcbc780"
    }
  }
]

Example Request for field:

JSON
[
  {
    "type": "field",
    "id": "5be5b1a8-eda5-42cf-b931-3a8e97c61b31",
    "name": "field 1234",
    "latitude": 100,
    "longitude": 100
  }
]

Example request for Static area creation

JSON
{
      "name": "static area test",
      "type": "area",
      "areaType": "STATIC",
      "fieldId": "5be5b1a8-eda5-42cf-b931-3a8e97c61b31",
      "teams": [
        {
          "teamId": "a6f2e572-c978-4f31-9fea-b512f940791c"
        },
        {
          "teamId": "df27e37c-04f7-45d0-99c9-ca330079adc6"
        },
        {
          "teamId": "34fc1cc5-1c55-4d50-ae3e-a8b15ed6ba9c"
        },
        {
          "teamId": "d43391d6-1c11-4910-91ec-9c0fb41de193"
        }
      ]
    }

Example request for Dynamic Area creation

JSON
[
  {
    "id": "e0a3d507-fb5a-4db0-b5e4-10d1a82e10c2",
    "name": "testStopAttributeArea",
    "type": "area",
    "areaType": "DYNAMIC",
    "fieldId": "5be5b1a8-eda5-42cf-b931-3a8e97c61b31",
    "additionalStopIds": [
      "2c089ea4-fb0b-4621-901b-98b8984155d7"
    ],
    "areaDefinition": {
      "criteria": [
        {
          "attributeName": "productType",
          "values": {
            "oil": true
          }
        }
      ]
    },
    "teams": [
      {
        "teamId": "team-001",
        "resources": [
          {
            "userId": "user-001",
            "resourceLevel": "operator"
          }
        ]
      }
    ]
  }
]

Example Response

JSON
{
  "success": true,
  "message": "Processed 1 items, Failed to process 0 items",
  "output": {
    "processedItems": [
      {
        "message": "Item got updated",
        "record": {
          "areas": [
            {
              "areaId": "8cc5fac8-1598-4794-b7fb-8a2796d17311",
              "isDeleted": false
            },
            {
              "areaId": "78469401-fd18-497d-ae10-39cf653da070",
              "isDeleted": false
            }
          ],
          "stopId": "35391454-7152-4f87-b17b-d7175552e225",
          "tenantId": "00e29a9d-6621-43a4-a6c2-a25c67939e5a",
          "customAttributes": {
            "C_DC_FLAG": "Yes",
            "Foreman": "harry, test"
          },
          "attachments": [],
          "createdBy": "shivar@sevenlakes.com",
          "name": "Gryffindor Common Room",
          "availability": [],
          "preferredLocations": {},
          "globalAttributes": {},
          "createdOn": "2023-07-05T10:07:54.862Z",
          "modifiedOn": "2025-08-04T04:16:11.520Z",
          "longitude": 100,
          "watchers": [],
          "description": "Godric gryffindor -testing1",
          "id": "35391454-7152-4f87-b17b-d7175552e225",
          "latitude": 100,
          "modifiedBy": "rajat.barman@sevenlakes.com",
          "fieldId": "5be5b1a8-eda5-42cf-b931-3a8e97c61b31",
          "type": "stop"
        }
      }
    ],
    "unProcessedItems": []
  }
}


13. Create vs Update

Create:

  1. If the asset (based on its identifiers) does not exist in the system, a new asset is created.

  2. Identifiers checked for existence:


id
xid
name
fdgxid

  1. If none of these match an existing asset for the tenant, the API will create a new record.

Update:

  1. If an asset with the same id, xid, name, or fdgxid already exists for the tenant, the API will update the existing asset with the new data provided in the request.

  2. The update is performed in-place, and only the fields provided in the request will be updated (others remain unchanged unless explicitly set to null or a new value).

14. How the API decides?

For each asset in the bulk array, the API tries to find an existing asset using the provided identifiers.

  • If a match is found, it’s an update; if not, it’s a create.

15. Dynamic Areas

A dynamic area is an area whose membership (e.g., which stops/assets belong to it) is determined automatically based on criteria, rather than being manually assigned.

This is achieved using the areaDefinition property, which specifies rules (criteria) for including assets in the area.

What makes an area “dynamic”?

  • Dynamic areas use the areaType: "DYNAMIC" property.

  • They include an areaDefinition object, which contains one or more criteria.

The system evaluates these criteria to automatically assign assets (like stops or wells) to the area, based on their attributes.

16. Area Definition

The areaDefinition property is required for dynamic areas and describes the rules for which assets should be included.
Structure:

JSON
"areaDefinition": {
  "criteria": [
    {
      "attributeName": "productType",
      "values": { "oil": true }
    },
    {
      "attributeName": "region",
      "values": { "north": true, "south": false }
    }
  ]
}
  • criteria: An array of objects, each specifying an attribute and the values that qualify an asset for inclusion in the area.

  • attributeName: The name of the asset attribute to check (e.g., "productType", "region").

  • values: An object where the keys are possible values for the attribute, and the values are booleans indicating inclusion.

How it works:

  • The system will automatically include all assets (e.g., stops, wells) in this area if their attributes match the criteria.

17. Teams in Dynamic Areas

You can assign teams to a dynamic area just like with static areas, using the teams property, allowing for access control and task assignment based on the dynamic membership of the area.

Structure:

JSON
"teams": [
  {
    "teamId": "team-001",
    "resources": [
      {
        "userId": "user-001",
        "resourceLevel": "operator"
      },
      {
        "userId": "user-002",
        "resourceLevel": "supervisor"
      }
    ]
  }
]
  • teamId: The unique identifier for the team.

  • resources: The users assigned to the team for this area, with their roles.

18. Area Team Mapping

You can assign teams (and their users) to an area asset by including a teams array in your area object when using the /api/asset/bulk endpoint.
How it works?

  1. When you include a teams array in an area asset, the system links those teams and users to the area.

  1. This mapping controls:

  • Access control: Only mapped teams/users can view or manage the area.

  • Task assignment: Tasks related to the area can be assigned to mapped teams/users.

  • Notifications: Only mapped teams/users receive area-related notifications.

  • Updating the teams array will update the mapping (add, remove, or change users/roles).

  • Notes:
    1. All teamId and userId values must reference existing teams and users.
    2. You can assign multiple teams to a single area.
    3. If you omit the teams property, no team mapping will be set or changed for that area.

19. Error Handling

Our API uses standard HTTP status codes to indicate the success or failure of a request. **Common Error Codes:** -

Code

Description

400 Bad Request

The request was invalid.

401 Unauthorized

Authentication failed: Verify Cognito User Pool configuration

404 Not Found

The requested resource was not found.

500 Internal Server Error

An error occurred on the server.

Error Response:
{"success":false,"message":"Some error message"}

20. Common Reasons for API Failure

Potential Issue

Resolution

improper date format

"2024-06-07T12:00:00.000Z"

format should be "2024-06-07 12:00:00.000"

Missing identifier (id, xid, name, fdgxid)

Provide at least one unique identifier for each asset.

Missing required field type

Ensure every asset object includes a valid "type" (e.g., "field", "route", etc.).

Invalid type value

Use only allowed values: "field", "route", "stop", "area", "well", "meter", "tank", "equipment".

Missing required reference (e.g., field for route/stop/area)

For child assets, include the required parent reference object (e.g., "field": {"xid": "FIELD_001"}).

Missing areaType for area asset

For "type": "area", always provide "areaType": "STATIC" or "DYNAMIC".

Missing areaDefinition for dynamic area

For "areaType": "DYNAMIC", include a valid "areaDefinition" object.

Reference object missing identifier

When providing references (e.g., field, route), ensure at least one of id, xid, name, or fdgxid is present.

Duplicate asset (same xid or name in same field)

Use unique xid and name values for each asset within the same field.

Invalid or missing team/user IDs in teams

Ensure all teamId and userId values in the teams array exist in the system.

Large request size

If the request is too large, split into smaller batches

Invalid attachment structure

Each attachment must include at least bucket and key.

Partial Success

Some records may fail while others succeed; always check unProcessedItems in the response.

21. Checks / Validations

#

Validation

1

All referenced fields, routes, stops, areas, and parent assets (by id/xid/name/fdgxid) are checked for existence.

2

All team IDs, user IDs, and user xids in the teams array are validated for existence.

3

All asset objects must have at least one valid identifier (id, xid, name, or fdgxid).

4

All entity names and xids must be unique within their parent context (e.g., field).

5

Custom attributes and metadata are validated for correct data types if schema is defined.

6

Authority/permission checks: Only users with the correct permissions can create/update assets.hecked, lower authority level cannot update higher authority level reading

7

Duplicate asset check: No two assets with the same xid or name in the same field.

8

Reference integrity: All references (e.g., field, route, stop, area) must point to existing, valid entities.

9

Area-specific checks: For type: "area", areaType and (if dynamic) areaDefinition are required and validated.

10

Area-specific checks: For type: "area", areaType and (if dynamic) areaDefinition are required and validated.

11

Partial upsert: Each asset is validated independently; failures in one do not block others.

12

Schema validation: All fields are checked against the asset schema for type and presence.

22. Setup Requirements

#

Requirement

1

Use Cognito JWT tokens for authentication.

2

Ensure your tenant and users are set up and have the right permissions.

3

Create parent assets before referencing them in child assets.

4

If using attachments, make sure S3 references are correct.

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.