Using the Bundle API

Combine multiple individual operations on Resources and Relationships into a single atomic action.

The Bundle API enables grouping multiple Resource and Relationship operations into a single Bundle Request, ensuring that all operations within the bundle are executed atomically. This makes it particularly well-suited for scenarios requiring transactional integrity across multiple Resources and Relationships.

Unlike the Bulk API, where operations are processed independently for records OR relationships, the Bundle API ensures all-or-nothing behaviour for all the operations within the same Bundle Request. If any operation in the bundle fails, the entire set of operations is cancelled.

Sending a Bundle Request

A Bundle Request comprises a collection of Resource operations and Relationship operations.

{
    "resourceOperations": [
        {
            "action": "CREATE",
            "create": {
                // Type, ID, Data, Contained and Meta
            }
        },
        {
            "action": "UPSERT",
            "upsert": {
                // ...
            }
        },
        {
            "action": "DELETE",
            "delete": {
                // ...
            }
        }
    ],
    "relationshipOperations": [
        {
            "action": "CREATE",
            "create": {
                // Type, ID, Data, Contained and Meta
            }
        },
        {
            "action": "UPSERT",
            "upsert": {
                // ...
            }
        },
        {
            "action": "DELETE",
            "delete": {
                // ...
            }
        }
    ]
}

📘

Notes

  • Only one operation per Resource and Relationship ID is allowed to prevent unexpected behavior (e.g., you cannot both DELETE and UPSERT the same resource in the same bundle).
  • Resource operations are processed before Relationship operations. This enables Relationship operations to reference Resource operations in the same bundle.
  • For more information on the specification, refer to the the API specification.

Example Use Case

Suppose you need to create an office, provider, and establish Relationships between them based on predefined profiles and relationship definitions. Using the Bundle API, this can be done in a single request:

{
    "resourceOperations": [
        {
            "action": "UPSERT",
            "upsert": {
                "id": "1",
                "type": "office",
                "data": {
                    "name": "Clinic Name"
                }
            }
        },
        {
            "action": "UPSERT",
            "upsert": {
                "id": "2",
                "type": "provider",
                "data": {
                    "name": "John Doe"
                }
            }
        }
    ],
    "relationshipOperations": [
        {
            "action": "UPSERT",
            "upsert": {
                "type": "provider-office",
                "from": {
                    "id": "1",
                    "type": "office"
                },
                "to": {
                    "id": "2",
                    "type": "provider"
                },
                "data": {
                    "description": "Works at"
                }
            }
        }
    ]
}

Bundle Response

Successful Bundle

When all operations in the bundle are valid, they are executed as a single, atomic transaction. The system ensures all operations are successfully completed and provides operation receipts with a SUCCESS status for each operation:

{
    "resourceOperationReceipts": [
        {
            "id": "1",
            "receivedAt": "2024-11-27T15:43:09.438665Z",
            "status": "SUCCESS",
            "type": "office"
        },
        {
            "id": "2",
            "receivedAt": "2024-11-27T15:43:09.438665Z",
            "status": "SUCCESS",
            "type": "provider"
        }
    ],
    "relationshipOperationReceipts": [
        {
            "id": "office.1,provider.2",
            "receivedAt": "2024-11-27T15:43:09.444574Z",
            "status": "SUCCESS",
            "type": "provider-office"
        }
    ]
}

❗️

Failed Bundle

If any operation in the bundle results in a FAILURE status, all other operations in the bundle are automatically CANCELLED maintaining the atomicity of the bundle. By reviewing the returned operation receipts, you may identify the errors that led to the failure:

{
    "resourceOperationReceipts": [
        {
            "error": {
                "code": 400,
                "details": [
                    {
                        "code": 400,
                        "message": "additionalProperties 'UNKNOWN' not allowed",
                        "type": "INVALID_ARGUMENT"
                    }
                ],
                "message": "invalid schema for office",
                "type": "FAILED_PRECONDITION"
            },
            "id": "1",
            "receivedAt": "2024-11-27T15:46:18.022606Z",
            "status": "FAILURE",
            "type": "office"
        },
        {
            "id": "2",
            "receivedAt": "2024-11-27T15:46:18.022606Z",
            "status": "CANCELLED",
            "type": "provider"
        }
    ],
    "relationshipOperationReceipts": [
        {
            "id": "office.1,provider.2",
            "receivedAt": "2024-11-27T15:46:18.030244Z",
            "status": "CANCELLED",
            "type": "provider-office"
        }
    ]
}

Advanced Feature: Virtual IDs

Virtual IDs act as placeholders, enabling the system to automatically generate actual Resource IDs during the execution of a Bundle Request.

📘

Notes

  • Virtual IDs follow the pattern "@rootId" followed by an integer (e.g., "@rootId1", "@rootId2", etc.).
  • Virtual IDs can be used for CREATEoperations only.

Example Request:

{
    "resourceOperations": [
        {
            "action": "CREATE",
            "create": {
                "id": "@rootId1", // Virtual ID #1
                "type": "office",
                "data": {
                    "name": "Clinic Name"
                }
            }
        },
        {
            "action": "CREATE",
            "create": {
                "id": "@rootId2", // Virtual ID #2
                "type": "provider",
                "data": {
                    "name": "John Doe"
                }
            }
        }
    ],
    "relationshipOperations": [
        {
            "action": "CREATE",
            "create": {
                "type": "provider-office",
                "from": {
                    "id": "@rootId1", // Virtual ID #1
                    "type": "office"
                },
                "to": {
                    "id": "@rootId2", // Virtual ID #2
                    "type": "provider"
                },
                "data": {
                    "description": "Works at"
                }
            }
        }
    ]
}

Example Response:

{
    "resourceOperationReceipts": [
        {
            "id": "2pUv7EdiOrKlphAYBtTKF0TwCM9",
            "receivedAt": "2024-11-28T22:34:58.94489Z",
            "status": "SUCCESS",
            "type": "office"
        },
        {
            "id": "2pUv7AQvsnalGn8I4RsBdKID8OR",
            "receivedAt": "2024-11-28T22:34:58.94489Z",
            "status": "SUCCESS",
            "type": "provider"
        }
    ],
      "relationshipOperationReceipts": [
        {
            "id": "office.2pUv7EdiOrKlphAYBtTKF0TwCM9,provider.2pUv7AQvsnalGn8I4RsBdKID8OR",
            "receivedAt": "2024-11-28T22:34:58.948208Z",
            "status": "SUCCESS",
            "type": "provider-office"
        }
    ]
}