PL-900 study materials
PL-900 study resources

Northwind: A Throttled Invoice-Approval Flow

PL-900 · Put your knowledge to work in context.

All case studies

Northwind: A Throttled Invoice-Approval Flow

A Power Automate cloud flow runs every 15 minutes, lists all rows in a Dataverse table of 4,000 pending invoice requests, and inside an Apply to each loop calls a vendor REST API that accepts 20 requests per minute. The API returns HTTP 429 with a Retry-After header when pushed harder. Runs currently fail with throttling errors, and finance reports duplicate approval emails: the same request sometimes gets two emails because the row's status is only updated at the end of the loop. Finance also needs a defensible audit trail of who approved what, with escalation if nobody responds in five days.

1. Restructure the flow so it respects the API's limits without dropping requests.

Read the worked answer

The core error is reading all 4,000 rows each run and firing calls with uncontrolled parallelism. Two changes address it.

First, narrow the query: filter the Dataverse list to status = Pending and take a bounded batch, so each run processes what 15 minutes of quota can absorb rather than the whole table. Second, set concurrency on the Apply to each explicitly to a value the quota supports - with a 20-per-minute ceiling, a small concurrency with sequential pacing or a delay is safer than the default.

Enable the retry policy on the HTTP action so a 429 is retried with backoff honouring Retry-After instead of failing the run. The judgement point is that throttling is a design constraint, not an error to suppress: if requests can wait, a queue that the flow drains at a controlled rate is more robust than a schedule that races the quota.

2. Eliminate the duplicate approval emails.

Read the worked answer

The duplicate is an idempotency bug, not an email bug. Because status is written once at the end of the loop, the next run re-reads rows that are already in flight and starts a second approval.

Fix it by claiming the row before acting: update the row to In progress as the first step inside the loop, conditional on the current status still being Pending, then send the approval. If the claim fails, skip the row. Better still, replace the blanket recurrence with a Dataverse trigger that fires when a row is created or when status changes to Pending, so the loop only ever sees new work.

Either approach makes the state transition the gate. Adding de-duplication in email will not survive a retry, because a retried action legitimately runs again.

3. Design the approval audit and five-day escalation. What must finance be able to prove later?

Read the worked answer

Use the built-in Approvals capability so each approval has an identifiable approver, a timestamp, and a recorded decision, rather than an email with a reply instruction. Set the approval's timeout to five days and branch on timeout to reassign to a named escalation owner, so silence produces a recorded outcome instead of a stalled row.

Write the outcome back to Dataverse - approver, decision, timestamp, and the source request - because approvals history has retention limits and finance's audit window will outlive it. The judgement is that the audit record must be owned by the business system, not by the flow run history, since run history expires and is not queryable for reporting.

Finally, decide who may approve before building: if approval rights depend on invoice amount, that routing belongs in a data table, not hard-coded in the flow.