Let me provide a comprehensive solution covering all three aspects: idempotency in microflows, callback error handling, and invoice reference tracking.
1. Idempotency in Microflows:
Implement a check-first pattern that makes your callback endpoint idempotent:
RETRIEVE Invoice WHERE InvoiceNumber = $CallbackData/invoiceNumber
AND TransactionID = $CallbackData/transactionID
IF $ExistingInvoice != empty THEN
RETURN CreateSuccessResponse($ExistingInvoice)
ELSE
// Create new invoice
END
The key is returning the exact same response structure whether you’re creating a new invoice or finding an existing one. The RPA robot cannot and should not distinguish between these scenarios.
2. Callback Error Handling:
Wrap your invoice creation in proper exception handling that returns success even on duplicate key violations:
TRY
CREATE Invoice
SET $Invoice/Number = $CallbackData/invoiceNumber
SET $Invoice/TransactionID = $CallbackData/transactionID
SET $Invoice/Amount = $CallbackData/amount
COMMIT $Invoice
RETURN CreateSuccessResponse($Invoice)
CATCH
IF $Error contains 'duplicate key' THEN
RETRIEVE Invoice WHERE InvoiceNumber = $CallbackData/invoiceNumber
RETURN CreateSuccessResponse($ExistingInvoice)
ELSE
RETURN CreateErrorResponse($Error)
END
END
This ensures that duplicate key violations (from database unique constraints) are handled gracefully and return success to prevent robot retries.
3. Invoice Reference Tracking:
Implement a composite key strategy using both invoice number and transaction ID:
- Add TransactionID attribute to your Invoice entity (String, required)
- Create unique constraint on combination of InvoiceNumber + TransactionID
- Store all callback attempts in a separate CallbackLog entity for audit trail
CallbackLog entity should track:
- TransactionID (from robot)
- InvoiceNumber
- Timestamp
- ResponseStatus
- RequestPayload (JSON string)
Complete Implementation Pattern:
Create a reusable microflow structure:
- Log incoming callback request immediately
- Validate required fields (invoice number, transaction ID, amount)
- Check for existing invoice by composite key
- If exists, return success with existing invoice ID
- If not exists, create within try-catch block
- On duplicate key error, retrieve and return existing
- On other errors, return proper error response with retry guidance
- Log final response status
Database Configuration:
In your domain model, set validation rules:
- InvoiceNumber: required, unique index
- TransactionID: required, unique index on (InvoiceNumber, TransactionID) combination
Integration Hub Configuration:
Set proper timeout values in your REST endpoint configuration (we use 30 seconds). Configure the endpoint to return consistent JSON structure:
{
"status": "success",
"invoiceId": "12345",
"message": "Invoice processed"
}
Return this structure whether it’s a new invoice or duplicate. This makes your API truly idempotent and prevents the robot from generating duplicates through retries. The combination of application-level checks and database constraints provides defense in depth against duplicate invoice creation.