Skip to content

what are the process flows and service components delivered in Azure subscription vending

Azure subscription vending is a process of programmatically provisioning and handing out Azure subscriptions to internal application teams in a standardized, governed way. It’s a key part of a well-architected Azure Landing Zone.

The core idea is to shift from a manual, ad-hoc process to an automated “vending machine” model. The platform team pre-packages and automates the delivery of subscriptions, enabling application teams to get a compliant, ready-to-use environment on demand.

⚙️ The Core Process Flow

The automation streamlines the request, setup, and delivery of a subscription. This flow is typically triggered by an application team’s request.

The process involves three key automated stages:

  • Stage 1: Collect Data: Application teams submit requests through a standardized form (e.g., a Power App or ITSM tool). This collects key information like cost center, expected budget, networking needs, and required Azure regions.
  • Stage 2: Initiate Automation: After approval, the system generates a parameter file (JSON/YAML) with the request details and commits it to a source control repository (like GitHub or Azure DevOps) as a Pull Request. This merge then triggers the deployment pipeline.
  • Stage 3: Create the Subscription: An automated CI/CD pipeline executes the request using Infrastructure as Code (IaC) modules (like Bicep or Terraform) to deliver a configured subscription.

📦 Service Components Delivered

The “vending” process automatically delivers a fully configured environment, typically including:

  • Azure Subscription: The core billing and security boundary. The automation creates it with a user-friendly display name and associated tags (e.g., CostCenter, Environment, Project).
  • Governance & Management: The subscription is automatically placed into a pre-defined management group (e.g., “Corp”, “Online”, “Sandbox”) which enforces baseline policies like allowed regions and data encryption. The process also creates a preliminary budget to set cost expectations.
  • Security & Access (RBAC): Azure role-based access control (RBAC) assignments are made, granting the application team appropriate permissions (e.g., Contributor) and securing access.
  • Core Networking: The process can create an empty virtual network (VNet) and automatically set up VNet peering to a central hub. This provides secure connectivity to on-premises or shared services and includes DDoS protection plans.
  • Azure Resource Providers: The system can pre-register common or project-specific resource providers (e.g., Microsoft.Compute, Microsoft.ContainerService), preventing deployment delays.

👤 Who Does What in the Process

Success relies on three key groups:

  • The Cloud Center of Excellence (CCoE): Defines the standardized “menu” of subscriptions (e.g., a “Tier 1” vs. “Sandbox” product line) and the business logic for approval.
  • The Application Team: Initiates the request and, after receiving the subscription, deploys and manages their workloads within it.
  • The Platform Team: Builds, maintains, and runs the automation pipeline that vends the subscriptions.

✅ Why Use Subscription Vending

This approach ensures every new subscription is compliant from day one and can be delivered in minutes rather than weeks, freeing your platform team to focus on higher-value tasks.

This is a significant investment in platform engineering, but for organizations operating at scale, it’s an essential one. If you’d like to explore specific implementation details, such as the technical configurations for Bicep or Terraform modules, feel free to ask.

give me a sample subscription vending workflow for a user to request an Azure subscription for s designated Azure landing zone, including a form with appropriate fields to fill in, approval stage gate, etc.

We need to provide a sample subscription vending workflow, including a request form and approval stage gate, similar to the earlier W365 example but for Azure subscription vending. The user wants a form, approval, and workflow. Should be practical, with fields, approval steps, and possibly integration with automation. Provide as a structured answer.

Here is a sample subscription vending workflow for requesting an Azure subscription within a designated Azure Landing Zone (ALZ), including a request form, approval stage gate, and automation handoff.

Overview: Azure Subscription Vending Workflow

Goal: Enable an application team to request a new Azure subscription that is automatically configured according to the enterprise Landing Zone policies (management group, policy assignments, RBAC, networking, budget alerts).

Actors:

  • Requester: Application lead or developer
  • Approver: Cloud Center of Excellence (CCoE) or FinOps owner
  • Automation Engine: Azure DevOps / GitHub Actions + IaC (Bicep/Terraform) + Azure Subscription Creation API

High-Level Steps:

  1. Requester fills out subscription request form
  2. Form triggers approval request to CCoE
  3. Upon approval, automation pipeline runs to create and configure subscription
  4. Subscription is handed over to the application team with all governance and connectivity in place

Part 1: Request Form for Azure Subscription Vending

Form Title: Azure Subscription Request – Landing Zone Enabled
Target: Enterprise Azure Landing Zone (e.g., Corp, Online, Sandbox)

Field

Type

Description / Options

Validation

Requester Name

Text

Full name

Required

Requester Email

Email

Work email

Required

Application/Project Name

Text

Name of the workload

Required

Cost Center

Text

Valid finance code

Required

Business Justification

Textarea

Why a new subscription is needed (vs existing)

Required

Landing Zone Type

Dropdown

• Corp (connected to on-prem)
• Online (internet-facing)
• Sandbox (no production)

Required

Environment Purpose

Dropdown

• Development/Test
• Production
• Shared Services
• Disaster Recovery

Required

Primary Azure Region

Dropdown

East US, West Europe, etc. (based on allowed regions)

Required

Secondary Region (DR)

Dropdown

Optional

Optional

Expected Monthly Spend

Number (USD)

Estimated budget

Required

Network Requirements

Checkboxes

• VNet peering to hub
• Direct on-prem connectivity
• No connectivity needed (isolated)

Required

Additional Azure Policies

Multiselect

• Deny public IPs
• Enforce tags
• Encrypt disks
• None

Optional

Requested Resource Providers

Multiselect

• Microsoft.Compute
• Microsoft.ContainerService
• Microsoft.Sql
• Microsoft.Storage

Optional

Subscription Name Alias

Text

Short name (e.g., myapp-dev) – used in management group path

Required, unique

Subscription Owner(s)

Text (emails)

Primary and backup owners (RBAC Owner role)

Required

Additional Contributor(s)

Text (emails)

Users/groups who need Contributor access

Optional

Start Date

Date

When subscription is needed

Required

End Date (if temporary)

Date

For sandbox subscriptions

Conditional

Form Footer:

By submitting, you agree that this subscription will be subject to automatic policy enforcement and monthly budget reviews. Unused subscriptions may be deprovisioned after 90 days of zero activity.

Part 2: Approval Stage Gate

Who Approves?

  • CCoE Lead or Cloud Governance Board – reviews for compliance, cost, and alignment with landing zone strategy.
  • For Sandbox subscriptions under a certain budget (e.g., < $200/month), auto-approval may be allowed.

Approval Workflow Steps:

  1. Review Request – Approver checks:
    • Is the landing zone type appropriate for the workload (e.g., production workloads cannot use Sandbox)?
    • Is the cost center valid and has sufficient remaining budget?
    • Does the naming convention follow standards?
    • Are the requested policies aligned with security requirements?
  2. Decision Options:
    • ✅ Approve → Proceed to subscription creation
    • ❌ Reject → Send reason back (e.g., “Use existing subscription”)
    • 🔄 Modify → Approver changes a field (e.g., region) and approves
  3. Escalation:
    • If no action in 2 business days → escalate to Cloud Governance Manager

Sample Approval Email

Subject: Azure Subscription Request – Action Required: [App/Project Name]

Requester: John Doe (john.doe@company.com)
Landing Zone Type: Corp
Environment: Production
Region: East US
Estimated monthly spend: $1,200
Justification: “New microservices platform – requires isolation”

[Approve] [Reject] [Modify Request]

View full request in Subscription Vending Portal

Part 3: Post-Approval – Automated Subscription Vending

Once approved, an automation pipeline (Azure DevOps or GitHub Actions) runs the following steps:

Step

Action

Tool / API

1. Create subscription

Call EA or MCA API to create new subscription under the specified enrollment account

Azure Billing API / ARM

2. Move to management group

Place subscription under the appropriate ALZ management group (e.g., Corp → Prod)

ARM / Policy API

3. Assign RBAC

Grant Owner role to primary owner(s), Contributor role to additional users/groups

Microsoft Graph / ARM

4. Apply Azure Policy

Assign built-in and custom policies (e.g., allowed regions, deny public IPs)

Policy assignments

5. Create budget & alert

Set budget = expected monthly spend, email alert at 80% and 100%

Consumption API

6. Configure networking

Create default VNet (optional), set up VNet peering to central hub if requested

ARM / Network API

7. Register resource providers

Register selected RPs at subscription level

ARM

8. Tag subscription

Apply required tags: CostCenter, Environment, LandingZoneType, ProjectName

ARM

9. Notify team

Send final email with subscription ID and portal link

Outlook / Teams

Estimated completion time: 5–15 minutes from approval.

Part 4: End-to-End User Journey

Step

Actor

System

1. User opens subscription request portal (SharePoint / Power App)

Requester

SharePoint / App Service

2. Fills and submits form

Requester

Form

3. Power Automate / Logic App triggers approval email

Automation

Outlook

4. CCoE approver reviews and clicks Approve

Approver

Outlook / Teams

5. Automation pipeline runs (IaC)

DevOps / GitHub

Azure APIs

6. Subscription created and configured

Automation

Azure

7. Notification sent to requester with subscription details

Automation

Email

8. Requester can now deploy workloads into the new subscription

Requester

Azure Portal / CLI

Part 5: Sample Implementation Options

Component

Technology Suggestion

Request frontend

SharePoint list + Power Apps (or Microsoft Forms)

Workflow & approval

Power Automate (or Azure Logic Apps)

Approval email

Outlook actionable messages

Subscription creation

Azure DevOps pipeline triggered by Power Automate (HTTP call)

IaC for subscription config

Bicep or Terraform modules

Audit log

SharePoint log list or Azure Log Analytics

Part 6: Audit & Historical Log (Same as previous pattern)

Create a Subscription Request Log SharePoint list to track:

  • Request ID
  • Requester
  • Landing Zone Type
  • Approval date
  • Approver name
  • Subscription ID (after creation)
  • Status (Submitted, Approved, Provisioned, Rejected)

Each approval action writes a log entry (as shown in the earlier answer).

Sample Flow Diagram (Simplified)

text

User submits form → SharePoint list item created

       ↓

Power Automate trigger → send approval email to CCoE

       ↓

CCoE approves (Outlook button)

       ↓

Power Automate calls Azure DevOps REST API to queue pipeline

       ↓

Pipeline runs Bicep/Terraform:

   – Create subscription

   – Assign to management group

   – Apply RBAC

   – Assign policies

   – Create VNet peering

   – Register RPs

       ↓

Pipeline returns subscription ID → Power Automate updates SharePoint

       ↓

Email sent to requester: “Your subscription is ready – ID: xxx”

Next Steps for Implementation

  1. Create the request form in SharePoint / Power Apps with the fields above.
  2. Build the Power Automate flow that:
    • Triggers on new item
    • Sends approval email (with actionable buttons)
    • On approval, calls Azure DevOps pipeline (or runs ARM directly)
  3. Develop the IaC module for subscription configuration (Bicep/Terraform).
  4. Set up the audit log SharePoint list.
  5. Test the full flow with a sandbox subscription offer.

Would you like me to provide the Power Automate flow JSON for this subscription vending workflow as well? Or the Bicep module for subscription configuration?

Yes. expand this into how this can be implemented as a sharepoint request front page with instructions to fill in a linked Sharepoint form, and power automate to automate the workflow with outlook/team email notifications

We need to produce a detailed implementation guide for an Azure subscription vending request system using SharePoint front page + SharePoint list form + Power Automate + Outlook/Teams notifications. The user wants expansion similar to the earlier W365 workflow but for subscription vending. Provide instructions, form fields, Power Automate flow logic, and integration with Azure subscription creation (likely via ARM or DevOps). Also include audit logging.

Here is a complete implementation guide for an Azure Subscription Vending request system using:

  • SharePoint Online – front page with instructions + a linked SharePoint list form
  • Power Automate – workflow engine for approvals and orchestration
  • Outlook / Microsoft Teams – notifications with actionable buttons
  • Azure DevOps – optional pipeline for subscription creation
  1. SharePoint Setup – Front Page & Request Form

1.1 Create a SharePoint Site

  • Example: https://yourtenant.sharepoint.com/sites/AzureSubscriptionVending

1.2 Create a SharePoint List – “Subscription Requests”

This list serves as both the request form and the data store.

Column Name

Type

Options / Notes

Title

Single line of text

Will store the Application/Project Name

RequesterEmail

Single line of text

Email address

CostCenter

Single line of text

Financial code

Justification

Multiple lines of text

Business need

LandingZoneType

Choice

Corp, Online, Sandbox

EnvironmentPurpose

Choice

Development/Test, Production, Shared Services, Disaster Recovery

PrimaryRegion

Choice

East US, West Europe, etc. (pre-filter allowed regions)

SecondaryRegion

Choice

Optional, can be blank

ExpectedMonthlySpend

Currency

USD estimate

NetworkRequirements

Choice (or multi-choice)

VNet peering to hub, Direct on-prem connectivity, Isolated

AdditionalPolicies

Multi-choice

Deny public IPs, Enforce tags, Encrypt disks

ResourceProviders

Multi-choice

Microsoft.Compute, Microsoft.ContainerService, Microsoft.Sql, Microsoft.Storage

SubscriptionAlias

Single line of text

e.g., myapp-prod – must be unique

SubscriptionOwners

Single line of text

Comma-separated emails

AdditionalContributors

Single line of text

Optional comma-separated emails

StartDate

Date

Required

EndDate

Date

Optional, for temporary subscriptions

Status

Choice

Submitted, Approved, Provisioning, Provisioned, Rejected (default: Submitted)

SubscriptionID

Single line of text

Populated after creation

ApproverComment

Multiple lines of text

Populated by Power Automate

Tip: Use “Require that this column contains information” for mandatory fields.

1.3 Customise the List Form (Optional with Power Apps)

  • Open the list → Integrate → Power Apps → Customise forms
  • Add conditional visibility: show EndDate only if user selects a temporary duration (you can add a “IsTemporary” Yes/No column to control this).

1.4 Create the SharePoint Front Page (Instructions)

Create a modern site page named “Request an Azure Subscription – Landing Zone”

Sample content:

Request a New Azure Subscription (Landing Zone Enabled)

Use this form to request a fully governed subscription in our enterprise Azure Landing Zone.

Before you begin

  • You must have a valid cost center.
  • Understand the difference between Corp, Online, and Sandbox landing zones ([link to internal doc]).
  • Production subscriptions require additional lead approval.

How to request

  1. Click the button below to open the request form.
  2. Fill in all required fields (marked with *).
  3. After submission, your CCoE approver will receive an email.
  4. Once approved, the subscription will be automatically created within 15 minutes.

[Request Subscription] – link to the SharePoint list new form:
https://yourtenant.sharepoint.com/sites/AzureSubscriptionVending/Lists/SubscriptionRequests/NewForm.aspx

Check status

View all your requests [here – link to a filtered view of the list].

  1. Power Automate – Workflow for Subscription Vending

2.1 Trigger

  • Flow name: Subscription Vending – Approval & Provisioning
  • Trigger: When an item is created (SharePoint)
    • Site address: your site
    • List name: Subscription Requests

2.2 Determine Approver (Dynamic or Static)

  • Option A (simple): Use a fixed CCoE email (e.g., cceo@company.com).
  • Option B (dynamic): Create a SharePoint list “LandingZoneApprovers” with columns LandingZoneType and ApproverEmail. Then in the flow, use Get items to fetch the approver based on the selected LandingZoneType.

2.3 Send Approval Notification (Outlook + Teams)

  • Use the Approvals connector: Start and wait for an approval
    • Approval type: Approve/Reject – First to respond
    • Title: Azure Subscription request: {Application Name}
    • Assigned to: [dynamic approver email]
    • Details: include all key fields (see below)
    • Enable actionable messages (Approve/Reject buttons in email)
    • Also send a Teams notification using the Post a message in a chat or channel action (Teams connector) to alert the approver.

Sample approval email body (HTML):

html

<b>Requester:</b> {RequesterEmail}<br>

<b>Project:</b> {Title}<br>

<b>Landing Zone Type:</b> {LandingZoneType}<br>

<b>Environment:</b> {EnvironmentPurpose}<br>

<b>Region:</b> {PrimaryRegion}<br>

<b>Est. monthly cost:</b> {ExpectedMonthlySpend}<br>

<b>Justification:</b> {Justification}<br>

<b>Subscription Alias:</b> {SubscriptionAlias}<br>

<br>

Click one of the buttons below to approve or reject.

2.4 Condition – Approval Outcome

Case: Approve

  1. Update SharePoint item – Status = Approved
  2. Create audit log entry (see section 4)
  3. Trigger subscription provisioning (two options):

Option A – Call Azure DevOps Pipeline (recommended)
Use the HTTP action to call Azure DevOps REST API to queue a pipeline.

    • Method: POST
    • URI: https://dev.azure.com/{org}/{project}/_apis/pipelines/{pipelineId}/runs?api-version=7.0
    • Headers: Authorization Basic with PAT (store as secret)
    • Body: JSON containing all request parameters (subscription alias, owners, region, etc.)

Option B – Direct ARM / Bicep via Azure Automation
Use Azure Automation runbook or Azure CLI task via a hybrid worker.
Simpler for demo: send an email to an IT shared mailbox with all details (semi-automated).

  1. Wait for provisioning completion (if using DevOps, you can poll the run status)
  2. Update SharePoint – Status = Provisioned, fill SubscriptionID
  3. Send final notification to requester (Outlook + Teams) with subscription details.

Case: Reject

  1. Update SharePoint – Status = Rejected, ApproverComment = approval comments
  2. Create audit log entry
  3. Send rejection email to requester with reason.

2.5 Timeout & Escalation (Optional)

  • Add a Delay action before the approval, then a second approval action assigned to a higher-level manager if no response in 48 hours.
  1. Integration with Azure Subscription Creation

3.1 Prerequisites

  • You must have an EA (Enterprise Agreement) or MCA (Microsoft Customer Agreement) with permission to create subscriptions using the Billing API.
  • Service principal with Subscription Creator role at the enrollment account level.
  • Pre-created management groups (e.g., Corp, Online, Sandbox).
  • Pre-created Azure Policies assigned at management group level (or to be assigned per subscription).

3.2 Sample Azure DevOps Pipeline (YAML) to Create Subscription

The pipeline can be triggered by Power Automate via REST API. It performs:

yaml

steps:

– task: AzureCLI@2

  inputs:

    azureSubscription: ‘ServicePrincipal-Creation’

    scriptType: ‘bash’

    scriptLocation: ‘inlineScript’

    inlineScript: |

      # Create subscription (EA)

      az account subscription create –enrollment-account-name “EA-123” \

        –offer-type “MS-AZR-0017G” \

        –display-name “$(SubscriptionAlias)” \

        –subscription-name “$(SubscriptionAlias)”

     

      # Get subscription ID

      SUB_ID=$(az account subscription list –query “[?displayName==’$(SubscriptionAlias)’].subscriptionId” -o tsv)

     

      # Move to management group

      az account management-group subscription add –name “$(LandingZoneType)” –subscription $SUB_ID

     

      # Assign RBAC (Owner to primary owners)

      for owner in $(echo “$(SubscriptionOwners)” | tr “,” ” “); do

        az role assignment create –assignee $owner –role Owner –subscription $SUB_ID

      done

     

      # Apply Azure Policy (example: deny public IPs)

      az policy assignment create –name “DenyPublicIPs” \

        –policy “/providers/Microsoft.Authorization/policyDefinitions/deny-public-ip” \

        –subscription $SUB_ID

     

      # Create budget alert

      az consumption budget create –budget-name “MonthlyBudget” \

        –subscription $SUB_ID \

        –amount $(ExpectedMonthlySpend) \

        –time-grain Monthly \

        –start-date $(date +%Y-%m-01) \

        –notifications “80Percent” –threshold-type Actual –operator GreaterThan –threshold 80 –contact-emails $(RequesterEmail)

     

      # Register resource providers

      for rp in $(echo “$(ResourceProviders)” | tr “,” ” “); do

        az provider register –namespace $rp –subscription $SUB_ID

      done

     

      echo “##vso[task.setvariable variable=SUB_ID;isOutput=true]$SUB_ID”

3.3 Call the Pipeline from Power Automate

After approval, add an HTTP action in Power Automate:

  • Method: POST
  • URI: https://dev.azure.com/{organization}/{project}/_apis/pipelines/{pipelineId}/runs?api-version=7.0
  • Headers:
    • Content-Type: application/json
    • Authorization: Basic [Base64 encoded PAT]
  • Body:

json

{

  “parameters”: {

    “SubscriptionAlias”: “@{triggerBody()?[‘SubscriptionAlias’]}”,

    “LandingZoneType”: “@{triggerBody()?[‘LandingZoneType’]}”,

    “SubscriptionOwners”: “@{triggerBody()?[‘SubscriptionOwners’]}”,

    “ExpectedMonthlySpend”: “@{triggerBody()?[‘ExpectedMonthlySpend’]}”,

    “RequesterEmail”: “@{triggerBody()?[‘RequesterEmail’]}”,

    “ResourceProviders”: “@{triggerBody()?[‘ResourceProviders’]}”

  }

}

Then poll the pipeline status (use a Delay + another HTTP GET) until completion, then retrieve the subscription ID from the pipeline output.

  1. Audit Log – Historical Record

Create a second SharePoint list: Subscription Vending Log

Column

Type

Description

Title

Single line

Auto: Request {ID} – {Action}

RequestID

Number

Link to original request ID

RequestTitle

Single line

Application/Project name

Action

Choice

Submitted, Approved, ProvisioningStarted, Provisioned, Rejected

Actor

Single line

Who performed action (email)

Timestamp

Date/Time

Default now

Comments

Multiple lines

Approver comments or system notes

StatusBefore

Single line

Previous status

StatusAfter

Single line

New status

In Power Automate, add Create item actions at each stage:

  • After trigger (Submitted)
  • After approval (Approved)
  • Before calling provisioning (ProvisioningStarted)
  • After subscription creation (Provisioned)
  • After rejection (Rejected)
  1. Complete End-to-End Flow Diagram

text

Requester opens SharePoint page → Clicks form link

       ↓

Fills and submits SharePoint list form

       ↓

Power Automate trigger (item created)

       ↓

Write audit log: “Submitted”

       ↓

Send approval email to CCoE (Outlook + Teams)

       ↓

Approver clicks Approve (actionable email/Teams)

       ↓

Power Automate condition: Approved?

       ↓ Yes

Write audit log: “Approved”

Update SharePoint status = “Approved”

       ↓

Call Azure DevOps pipeline (HTTP)

Write audit log: “ProvisioningStarted”

       ↓

Pipeline runs:

   – Create subscription

   – Assign to management group

   – RBAC, policies, budget, RPs

       ↓

Pipeline returns subscription ID

       ↓

Update SharePoint: Status=”Provisioned”, SubscriptionID

Write audit log: “Provisioned”

       ↓

Send final email/Teams message to requester:

   “Your subscription is ready. ID: xxx”

       ↓

(If reject) Write log “Rejected”, send rejection email.

  1. Example Teams Notification for Approval

Use the Post a message in a chat or channel action (Teams connector) with:

  • Post as: Flow bot
  • Message:

text

**New Azure Subscription Request**

– Project: {Title}

– Requester: {RequesterEmail}

– Landing Zone: {LandingZoneType}

– Est. cost: {ExpectedMonthlySpend}

 

[Approve](link to approval action) | [Reject](link)

But for actionable messages, the Approvals connector already supports Teams. Use the same approval action; it will appear in Teams as an adaptive card if Teams is the notification destination.

  1. Sample Power Automate Flow (Simplified JSON Structure)

json

{

  “triggers”: {

    “When_an_item_is_created”: { … }

  },

  “actions”: {

    “Create_audit_log_submitted”: { … },

    “Send_approval”: {

      “type”: “ApiConnection”,

      “inputs”: {

        “host”: { “connectionName”: “shared_approvals” },

        “operationId”: “SendApproval”,

        “parameters”: {

          “approvalType”: “ApproveRejectFirstToRespond”,

          “title”: “@{triggerBody()?[‘Title’]} – Subscription Request”,

          “assignedTo”: “cceo@company.com”,

          “details”: “…”,

          “enableActionableMessages”: true

        }

      }

    },

    “Condition_approved”: {

      “type”: “If”,

      “expression”: { “equals”: [“@body(‘Send_approval’)?[‘result’]?[‘outcome’]”, “Approve”] },

      “actions”: {

        “Update_SP_approved”: { … },

        “Create_audit_log_approved”: { … },

        “Call_DevOps_pipeline”: {

          “type”: “Http”,

          “inputs”: {

            “method”: “POST”,

            “uri”: “https://dev.azure.com/…/runs?api-version=7.0”,

            “headers”: { “Authorization”: “Basic …” },

            “body”: { … }

          }

        },

        “Poll_pipeline_status”: { … },

        “Update_SP_provisioned”: { … },

        “Send_final_email”: { … }

      },

      “else”: {

        “actions”: {

          “Update_SP_rejected”: { … },

          “Send_rejection_email”: { … }

        }

      }

    }

  }

}

  1. Testing Checklist
  • SharePoint list created with all columns.
  • Power Automate flow imported and connections reconfigured (SharePoint, Approvals, Outlook, Teams, HTTP).
  • Service principal or PAT configured for Azure DevOps API.
  • Test with a small budget sandbox subscription.
  • Verify audit log entries are created.
  • Confirm Teams notifications are received (if configured).

Next Steps

  1. Build the SharePoint list using the schema above.
  2. Create the Power Automate flow – start with the approval part, then add the provisioning call.
  3. Set up the Azure DevOps pipeline (or start with a manual email handoff for testing).
  4. Add the audit log list and integrate logging actions.
  5. Test end-to-end with a real subscription creation (use a test EA account if possible).

Would you like me to provide the complete Power Automate export JSON for this subscription vending flow (including the HTTP call to Azure DevOps and audit log creation)? Just let me know.

power automate export package please

We need to provide a Power Automate export package for the Azure subscription vending workflow. The user asked “power automate export package please” in the context of the subscription vending workflow. I’ll provide the flow definition JSON that can be imported into Power Automate, similar to the previous W365 example but now for subscription vending. I’ll include the necessary placeholders and instructions.

Below is the Power Automate flow definition JSON for the Azure Subscription Vending workflow. You can import this into your Power Automate environment and reconfigure the connections.

How to Import

  1. Copy the JSON below into a file named SubscriptionVending_Flow.json
  2. In Power Automate → My flows → Import → Select file → upload the JSON
  3. After import, you will be prompted to set up connections for:
    • SharePoint
    • Approvals
    • Outlook
    • Microsoft Teams
    • HTTP (for Azure DevOps)
  4. Update all placeholders (marked with YOUR_…) in the flow actions (SharePoint site address, approver email, Azure DevOps details, etc.)
  5. Turn on the flow

Flow Definition JSON

json

{

  “$schema”: “https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#”,

  “contentVersion”: “1.0.0.0”,

  “parameters”: {

    “$connections”: {

      “defaultValue”: {},

      “type”: “Object”

    }

  },

  “triggers”: {

    “When_an_item_is_created”: {

      “type”: “ApiConnection”,

      “inputs”: {

        “host”: {

          “connectionName”: “shared_sharepointonline”,

          “operationId”: “WhenItemCreated”

        },

        “parameters”: {

          “siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,

          “listName”: “Subscription Requests”

        },

        “authentication”: {

          “type”: “Raw”,

          “scheme”: “Key”,

          “parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”

        }

      },

      “recurrence”: {

        “frequency”: “Second”,

        “interval”: 60

      },

      “splitOn”: “@triggerBody()?[‘value’]”

    }

  },

  “actions”: {

    “Get_item_details”: {

      “type”: “ApiConnection”,

      “inputs”: {

        “host”: {

          “connectionName”: “shared_sharepointonline”,

          “operationId”: “GetItem”

        },

        “parameters”: {

          “siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,

          “listName”: “Subscription Requests”,

          “id”: “@triggerBody()?[‘ID’]”

        },

        “authentication”: {

          “type”: “Raw”,

          “scheme”: “Key”,

          “parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”

        }

      },

      “runAfter”: {}

    },

    “Create_audit_log_submitted”: {

      “type”: “ApiConnection”,

      “inputs”: {

        “host”: {

          “connectionName”: “shared_sharepointonline”,

          “operationId”: “CreateItem”

        },

        “parameters”: {

          “siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,

          “listName”: “Subscription Vending Log”,

          “item”: {

            “Title”: “Request @{triggerBody()?[‘ID’]} – Submitted”,

            “RequestID”: “@{triggerBody()?[‘ID’]}”,

            “RequestTitle”: “@{triggerBody()?[‘Title’]}”,

            “Action”: “Submitted”,

            “Actor”: “@{triggerBody()?[‘RequesterEmail’]}”,

            “Timestamp”: “@{utcNow()}”,

            “Comments”: “@{triggerBody()?[‘Justification’]}”,

            “StatusBefore”: “”,

            “StatusAfter”: “Submitted”

          }

        },

        “authentication”: {

          “type”: “Raw”,

          “scheme”: “Key”,

          “parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”

        }

      },

      “runAfter”: {

        “Get_item_details”: [“Succeeded”]

      }

    },

    “Initialize_approver_email”: {

      “type”: “InitializeVariable”,

      “inputs”: {

        “variables”: [

          {

            “name”: “ApproverEmail”,

            “type”: “string”,

            “value”: “cceo@yourcompany.com”

          }

        ]

      },

      “runAfter”: {

        “Create_audit_log_submitted”: [“Succeeded”]

      }

    },

    “Send_approval_email”: {

      “type”: “ApiConnection”,

      “inputs”: {

        “host”: {

          “connectionName”: “shared_approvals”,

          “operationId”: “SendApproval”

        },

        “parameters”: {

          “approvalType”: “ApproveRejectFirstToRespond”,

          “title”: “Azure Subscription Request: @{triggerBody()?[‘Title’]}”,

          “assignedTo”: “@variables(‘ApproverEmail’)”,

          “details”: “<b>Requester:</b> @{triggerBody()?[‘RequesterEmail’]}<br><b>Project:</b> @{triggerBody()?[‘Title’]}<br><b>Landing Zone Type:</b> @{triggerBody()?[‘LandingZoneType’]}<br><b>Environment:</b> @{triggerBody()?[‘EnvironmentPurpose’]}<br><b>Region:</b> @{triggerBody()?[‘PrimaryRegion’]}<br><b>Est. monthly cost:</b> @{triggerBody()?[‘ExpectedMonthlySpend’]}<br><b>Justification:</b> @{triggerBody()?[‘Justification’]}<br><b>Subscription Alias:</b> @{triggerBody()?[‘SubscriptionAlias’]}<br><br>Click one of the buttons below to approve or reject.”,

          “itemLink”: “YOUR_SHAREPOINT_SITE_URL/Lists/SubscriptionRequests/DispForm.aspx?ID=@{triggerBody()?[‘ID’]}”,

          “notificationType”: “Email”,

          “enableActionableMessages”: true

        },

        “authentication”: {

          “type”: “Raw”,

          “scheme”: “Key”,

          “parameter”: “$connections[‘shared_approvals’][‘connectionId’]”

        }

      },

      “runAfter”: {

        “Initialize_approver_email”: [“Succeeded”]

      }

    },

    “Send_Teams_approval_notification”: {

      “type”: “ApiConnection”,

      “inputs”: {

        “host”: {

          “connectionName”: “shared_teams”,

          “operationId”: “PostMessageToChannel”

        },

        “parameters”: {

          “team”: “YOUR_TEAM_ID”,

          “channel”: “YOUR_CHANNEL_ID”,

          “message”: “**New Azure Subscription Request**\n- Project: @{triggerBody()?[‘Title’]}\n- Requester: @{triggerBody()?[‘RequesterEmail’]}\n- Landing Zone: @{triggerBody()?[‘LandingZoneType’]}\n- Est. cost: @{triggerBody()?[‘ExpectedMonthlySpend’]}\n\n[Approve or Reject in Outlook]”

        },

        “authentication”: {

          “type”: “Raw”,

          “scheme”: “Key”,

          “parameter”: “$connections[‘shared_teams’][‘connectionId’]”

        }

      },

      “runAfter”: {

        “Send_approval_email”: [“Succeeded”]

      }

    },

    “Condition_approval_outcome”: {

      “type”: “If”,

      “expression”: {

        “equals”: [

          “@body(‘Send_approval_email’)?[‘result’]?[‘outcome’]”,

          “Approve”

        ]

      },

      “actions”: {

        “Update_SharePoint_status_approved”: {

          “type”: “ApiConnection”,

          “inputs”: {

            “host”: {

              “connectionName”: “shared_sharepointonline”,

              “operationId”: “UpdateItem”

            },

            “parameters”: {

              “siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,

              “listName”: “Subscription Requests”,

              “id”: “@triggerBody()?[‘ID’]”,

              “item”: {

                “Status”: “Approved”

              }

            },

            “authentication”: {

              “type”: “Raw”,

              “scheme”: “Key”,

              “parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”

            }

          },

          “runAfter”: {}

        },

        “Create_audit_log_approved”: {

          “type”: “ApiConnection”,

          “inputs”: {

            “host”: {

              “connectionName”: “shared_sharepointonline”,

              “operationId”: “CreateItem”

            },

            “parameters”: {

              “siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,

              “listName”: “Subscription Vending Log”,

              “item”: {

                “Title”: “Request @{triggerBody()?[‘ID’]} – Approved”,

                “RequestID”: “@{triggerBody()?[‘ID’]}”,

                “RequestTitle”: “@{triggerBody()?[‘Title’]}”,

                “Action”: “Approved”,

                “Actor”: “@{body(‘Send_approval_email’)?[‘responder’]?[’email’]}”,

                “Timestamp”: “@{utcNow()}”,

                “Comments”: “@{body(‘Send_approval_email’)?[‘result’]?[‘comments’]}”,

                “StatusBefore”: “Submitted”,

                “StatusAfter”: “Approved”

              }

            },

            “authentication”: {

              “type”: “Raw”,

              “scheme”: “Key”,

              “parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”

            }

          },

          “runAfter”: {

            “Update_SharePoint_status_approved”: [“Succeeded”]

          }

        },

        “Call_DevOps_pipeline”: {

          “type”: “Http”,

          “inputs”: {

            “method”: “POST”,

            “uri”: “https://dev.azure.com/YOUR_ORG/YOUR_PROJECT/_apis/pipelines/YOUR_PIPELINE_ID/runs?api-version=7.0”,

            “headers”: {

              “Content-Type”: “application/json”,

              “Authorization”: “Basic YOUR_BASE64_PAT”

            },

            “body”: {

              “parameters”: {

                “SubscriptionAlias”: “@{triggerBody()?[‘SubscriptionAlias’]}”,

                “LandingZoneType”: “@{triggerBody()?[‘LandingZoneType’]}”,

                “SubscriptionOwners”: “@{triggerBody()?[‘SubscriptionOwners’]}”,

                “AdditionalContributors”: “@{triggerBody()?[‘AdditionalContributors’]}”,

                “ExpectedMonthlySpend”: “@{triggerBody()?[‘ExpectedMonthlySpend’]}”,

                “RequesterEmail”: “@{triggerBody()?[‘RequesterEmail’]}”,

                “PrimaryRegion”: “@{triggerBody()?[‘PrimaryRegion’]}”,

                “ResourceProviders”: “@{triggerBody()?[‘ResourceProviders’]}”

              }

            }

          },

          “runAfter”: {

            “Create_audit_log_approved”: [“Succeeded”]

          }

        },

        “Delay_for_provisioning”: {

          “type”: “Delay”,

          “inputs”: {

            “interval”: {

              “count”: 30,

              “unit”: “Second”

            }

          },

          “runAfter”: {

            “Call_DevOps_pipeline”: [“Succeeded”]

          }

        },

        “Get_pipeline_run_status”: {

          “type”: “Http”,

          “inputs”: {

            “method”: “GET”,

            “uri”: “@{outputs(‘Call_DevOps_pipeline’)?[‘headers’]?[‘Location’]}”,

            “headers”: {

              “Authorization”: “Basic YOUR_BASE64_PAT”

            }

          },

          “runAfter”: {

            “Delay_for_provisioning”: [“Succeeded”]

          }

        },

        “Condition_pipeline_success”: {

          “type”: “If”,

          “expression”: {

            “equals”: [

              “@body(‘Get_pipeline_run_status’)?[‘state’]”,

              “completed”

            ]

          },

          “actions”: {

            “Update_SharePoint_provisioned”: {

              “type”: “ApiConnection”,

              “inputs”: {

                “host”: {

                  “connectionName”: “shared_sharepointonline”,

                  “operationId”: “UpdateItem”

                },

                “parameters”: {

                  “siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,

                  “listName”: “Subscription Requests”,

                  “id”: “@triggerBody()?[‘ID’]”,

                  “item”: {

                    “Status”: “Provisioned”,

                    “SubscriptionID”: “@body(‘Get_pipeline_run_status’)?[‘result’]?[‘subscriptionId’]”

                  }

                },

                “authentication”: {

                  “type”: “Raw”,

                  “scheme”: “Key”,

                  “parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”

                }

              },

              “runAfter”: {}

            },

            “Create_audit_log_provisioned”: {

              “type”: “ApiConnection”,

              “inputs”: {

                “host”: {

                  “connectionName”: “shared_sharepointonline”,

                  “operationId”: “CreateItem”

                },

                “parameters”: {

                  “siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,

                  “listName”: “Subscription Vending Log”,

                  “item”: {

                    “Title”: “Request @{triggerBody()?[‘ID’]} – Provisioned”,

                    “RequestID”: “@{triggerBody()?[‘ID’]}”,

                    “RequestTitle”: “@{triggerBody()?[‘Title’]}”,

                    “Action”: “Provisioned”,

                    “Actor”: “System”,

                    “Timestamp”: “@{utcNow()}”,

                    “Comments”: “Subscription ID: @{body(‘Get_pipeline_run_status’)?[‘result’]?[‘subscriptionId’]}”,

                    “StatusBefore”: “Approved”,

                    “StatusAfter”: “Provisioned”

                  }

                },

                “authentication”: {

                  “type”: “Raw”,

                  “scheme”: “Key”,

                  “parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”

                }

              },

              “runAfter”: {

                “Update_SharePoint_provisioned”: [“Succeeded”]

              }

            },

            “Send_final_success_email”: {

              “type”: “ApiConnection”,

              “inputs”: {

                “host”: {

                  “connectionName”: “shared_outlook”,

                  “operationId”: “SendEmail”

                },

                “parameters”: {

                  “emailMessage”: {

                    “To”: “@{triggerBody()?[‘RequesterEmail’]}”,

                    “Subject”: “Your Azure subscription is ready”,

                    “Body”: “Dear @{triggerBody()?[‘Title’]},\n\nYour requested Azure subscription has been provisioned successfully.\n\n**Subscription ID:** @{body(‘Get_pipeline_run_status’)?[‘result’]?[‘subscriptionId’]}\n**Landing Zone Type:** @{triggerBody()?[‘LandingZoneType’]}\n\nYou can now access it in the Azure portal.\n\nRequest ID: @{triggerBody()?[‘ID’]}\n\nThank you.”

                  }

                },

                “authentication”: {

                  “type”: “Raw”,

                  “scheme”: “Key”,

                  “parameter”: “$connections[‘shared_outlook’][‘connectionId’]”

                }

              },

              “runAfter”: {

                “Create_audit_log_provisioned”: [“Succeeded”]

              }

            }

          },

          “else”: {

            “actions”: {

              “Send_provisioning_failure_alert”: {

                “type”: “ApiConnection”,

                “inputs”: {

                  “host”: {

                    “connectionName”: “shared_outlook”,

                    “operationId”: “SendEmail”

                  },

                  “parameters”: {

                    “emailMessage”: {

                      “To”: “cceo@yourcompany.com”,

                      “Subject”: “Subscription provisioning failed for @{triggerBody()?[‘Title’]}”,

                      “Body”: “The automated provisioning pipeline failed. Please check Azure DevOps run logs.\n\nRequest ID: @{triggerBody()?[‘ID’]}\nSubscription Alias: @{triggerBody()?[‘SubscriptionAlias’]}”

                    }

                  },

                  “authentication”: {

                    “type”: “Raw”,

                    “scheme”: “Key”,

                    “parameter”: “$connections[‘shared_outlook’][‘connectionId’]”

                  }

                },

                “runAfter”: {}

              }

            }

          },

          “runAfter”: {

            “Get_pipeline_run_status”: [“Succeeded”]

          }

        }

      },

      “else”: {

        “actions”: {

          “Update_SharePoint_status_rejected”: {

            “type”: “ApiConnection”,

            “inputs”: {

              “host”: {

                “connectionName”: “shared_sharepointonline”,

                “operationId”: “UpdateItem”

              },

              “parameters”: {

                “siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,

                “listName”: “Subscription Requests”,

                “id”: “@triggerBody()?[‘ID’]”,

                “item”: {

                  “Status”: “Rejected”,

                  “ApproverComment”: “@{body(‘Send_approval_email’)?[‘result’]?[‘comments’]}”

                }

              },

              “authentication”: {

                “type”: “Raw”,

                “scheme”: “Key”,

                “parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”

              }

            },

            “runAfter”: {}

          },

          “Create_audit_log_rejected”: {

            “type”: “ApiConnection”,

            “inputs”: {

              “host”: {

                “connectionName”: “shared_sharepointonline”,

                “operationId”: “CreateItem”

              },

              “parameters”: {

                “siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,

                “listName”: “Subscription Vending Log”,

                “item”: {

                  “Title”: “Request @{triggerBody()?[‘ID’]} – Rejected”,

                  “RequestID”: “@{triggerBody()?[‘ID’]}”,

                  “RequestTitle”: “@{triggerBody()?[‘Title’]}”,

                  “Action”: “Rejected”,

                  “Actor”: “@{body(‘Send_approval_email’)?[‘responder’]?[’email’]}”,

                  “Timestamp”: “@{utcNow()}”,

                  “Comments”: “@{body(‘Send_approval_email’)?[‘result’]?[‘comments’]}”,

                  “StatusBefore”: “Submitted”,

                  “StatusAfter”: “Rejected”

                }

              },

              “authentication”: {

                “type”: “Raw”,

                “scheme”: “Key”,

                “parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”

              }

            },

            “runAfter”: {

              “Update_SharePoint_status_rejected”: [“Succeeded”]

            }

          },

          “Send_rejection_email_to_requester”: {

            “type”: “ApiConnection”,

            “inputs”: {

              “host”: {

                “connectionName”: “shared_outlook”,

                “operationId”: “SendEmail”

              },

              “parameters”: {

                “emailMessage”: {

                  “To”: “@{triggerBody()?[‘RequesterEmail’]}”,

                  “Subject”: “Your Azure subscription request was not approved”,

                  “Body”: “Dear @{triggerBody()?[‘Title’]},\n\nYour request for a new Azure subscription has been **rejected** by the approver.\n\n**Reason:** @{body(‘Send_approval_email’)?[‘result’]?[‘comments’]}\n\nIf you believe this is an error, please contact the Cloud Center of Excellence.”

                }

              },

              “authentication”: {

                “type”: “Raw”,

                “scheme”: “Key”,

                “parameter”: “$connections[‘shared_outlook’][‘connectionId’]”

              }

            },

            “runAfter”: {

              “Create_audit_log_rejected”: [“Succeeded”]

            }

          }

        }

      },

      “runAfter”: {

        “Send_Teams_approval_notification”: [“Succeeded”]

      }

    }

  },

  “outputs”: {}

}

Important Placeholders to Replace

Placeholder

Where to find in the flow

Example value

YOUR_SHAREPOINT_SITE_URL

Multiple actions (trigger, get item, update, create log)

https://contoso.sharepoint.com/sites/AzureSubscriptionVending

cceo@yourcompany.com

Initialize_approver_email variable

Actual CCoE email address

YOUR_TEAM_ID & YOUR_CHANNEL_ID

Send_Teams_approval_notification action

Obtained from Teams connector

YOUR_ORG, YOUR_PROJECT, YOUR_PIPELINE_ID

Call_DevOps_pipeline HTTP action

contoso, SubscriptionVending, 42

YOUR_BASE64_PAT

HTTP actions (authorization header)

Convert :PAT to Base64 (e.g., OmFhYmNk…)

Prerequisites Before Import

  1. SharePoint lists must exist:
    • Subscription Requests (columns as defined in earlier answer)
    • Subscription Vending Log (columns as defined)
  2. Azure DevOps pipeline (optional but recommended) – a pipeline that accepts the parameters and returns subscriptionId in its output.
  3. Approvals connector – will be automatically added when you set up connections.
  4. Teams connector – if you want Teams notifications.

Testing After Import

  1. Create a new item in the Subscription Requests list.
  2. The flow should trigger within 1 minute.
  3. Approver receives an email with Approve/Reject buttons.
  4. After clicking Approve, the flow calls Azure DevOps.
  5. Check the audit log list for entries: Submitted → Approved → Provisioned.

Let me know if you need a simplified version without Azure DevOps (e.g., email handoff to IT) or a version with escalation and auto‑expiry. I can provide those JSON snippets as well.

show me the version with email handoff to IT

We need to provide a simplified version of the Power Automate flow that uses email handoff to IT instead of Azure DevOps API. The user wants “email handoff to IT” meaning after approval, an email is sent to an IT team (shared mailbox) with all the details, and IT will manually provision the subscription. The flow still includes the SharePoint front page, form, approval stage gate, audit log, and notifications. We’ll produce the JSON for this simplified flow.

We’ll adapt the previous JSON: remove HTTP calls to Azure DevOps, replace with a “Send email to IT” action. Also remove pipeline polling logic. Keep audit log entries for “Submitted”, “Approved”, “Rejected”, and add “Handed off to IT” (or similar). We’ll keep Teams notification optional.

Let’s produce the answer with explanation and the JSON.

Here is the simplified Power Automate flow JSON that uses email handoff to IT instead of direct Azure DevOps integration. After approval, an email is sent to an IT shared mailbox containing all subscription request details. IT then manually provisions the subscription.

Flow Overview (Email Handoff to IT)

text

User submits SharePoint form

       ↓

Flow trigger: item created

       ↓

Audit log: “Submitted”

       ↓

Send approval email to CCoE (Outlook + Teams optional)

       ↓

Approver clicks Approve/Reject (actionable email)

       ↓

If Approved:

   – Update SharePoint status → “Approved”

   – Audit log: “Approved”

   – Send email to IT shared mailbox with all request details

   – Audit log: “Handed off to IT”

   – Notify requester: “Request approved, IT will provision”

If Rejected:

   – Update SharePoint status → “Rejected”

   – Audit log: “Rejected”

   – Email requester with rejection reason

No HTTP calls, no pipeline polling, no complex waits.

How to Import

  1. Copy the JSON below into a file named SubscriptionVending_EmailHandoff.json
  2. In Power Automate → My flows → Import → Select file → upload
  3. Reconfigure connections: SharePoint, Approvals, Outlook, Teams (optional)
  4. Replace all placeholders (YOUR_SHAREPOINT_SITE_URL, cceo@yourcompany.com, it-team@yourcompany.com, etc.)
  5. Turn on the flow

Flow Definition JSON (Email Handoff to IT)

json

{

  “$schema”: “https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#”,

  “contentVersion”: “1.0.0.0”,

  “parameters”: {

    “$connections”: {

      “defaultValue”: {},

      “type”: “Object”

    }

  },

  “triggers”: {

    “When_an_item_is_created”: {

      “type”: “ApiConnection”,

      “inputs”: {

        “host”: {

          “connectionName”: “shared_sharepointonline”,

          “operationId”: “WhenItemCreated”

        },

        “parameters”: {

          “siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,

          “listName”: “Subscription Requests”

        },

        “authentication”: {

          “type”: “Raw”,

          “scheme”: “Key”,

          “parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”

        }

      },

      “recurrence”: {

        “frequency”: “Second”,

        “interval”: 60

      },

      “splitOn”: “@triggerBody()?[‘value’]”

    }

  },

  “actions”: {

    “Get_item_details”: {

      “type”: “ApiConnection”,

      “inputs”: {

        “host”: {

          “connectionName”: “shared_sharepointonline”,

          “operationId”: “GetItem”

        },

        “parameters”: {

          “siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,

          “listName”: “Subscription Requests”,

          “id”: “@triggerBody()?[‘ID’]”

        },

        “authentication”: {

          “type”: “Raw”,

          “scheme”: “Key”,

          “parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”

        }

      },

      “runAfter”: {}

    },

    “Create_audit_log_submitted”: {

      “type”: “ApiConnection”,

      “inputs”: {

        “host”: {

          “connectionName”: “shared_sharepointonline”,

          “operationId”: “CreateItem”

        },

        “parameters”: {

          “siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,

          “listName”: “Subscription Vending Log”,

          “item”: {

            “Title”: “Request @{triggerBody()?[‘ID’]} – Submitted”,

            “RequestID”: “@{triggerBody()?[‘ID’]}”,

            “RequestTitle”: “@{triggerBody()?[‘Title’]}”,

            “Action”: “Submitted”,

            “Actor”: “@{triggerBody()?[‘RequesterEmail’]}”,

            “Timestamp”: “@{utcNow()}”,

            “Comments”: “@{triggerBody()?[‘Justification’]}”,

            “StatusBefore”: “”,

            “StatusAfter”: “Submitted”

          }

        },

        “authentication”: {

          “type”: “Raw”,

          “scheme”: “Key”,

          “parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”

        }

      },

      “runAfter”: {

        “Get_item_details”: [“Succeeded”]

      }

    },

    “Initialize_approver_email”: {

      “type”: “InitializeVariable”,

      “inputs”: {

        “variables”: [

          {

            “name”: “ApproverEmail”,

            “type”: “string”,

            “value”: “cceo@yourcompany.com”

          }

        ]

      },

      “runAfter”: {

        “Create_audit_log_submitted”: [“Succeeded”]

      }

    },

    “Send_approval_email”: {

      “type”: “ApiConnection”,

      “inputs”: {

        “host”: {

          “connectionName”: “shared_approvals”,

          “operationId”: “SendApproval”

        },

        “parameters”: {

          “approvalType”: “ApproveRejectFirstToRespond”,

          “title”: “Azure Subscription Request: @{triggerBody()?[‘Title’]}”,

          “assignedTo”: “@variables(‘ApproverEmail’)”,

          “details”: “<b>Requester:</b> @{triggerBody()?[‘RequesterEmail’]}<br><b>Project:</b> @{triggerBody()?[‘Title’]}<br><b>Landing Zone Type:</b> @{triggerBody()?[‘LandingZoneType’]}<br><b>Environment:</b> @{triggerBody()?[‘EnvironmentPurpose’]}<br><b>Region:</b> @{triggerBody()?[‘PrimaryRegion’]}<br><b>Est. monthly cost:</b> @{triggerBody()?[‘ExpectedMonthlySpend’]}<br><b>Justification:</b> @{triggerBody()?[‘Justification’]}<br><b>Subscription Alias:</b> @{triggerBody()?[‘SubscriptionAlias’]}<br><br>Click one of the buttons below to approve or reject.”,

          “itemLink”: “YOUR_SHAREPOINT_SITE_URL/Lists/SubscriptionRequests/DispForm.aspx?ID=@{triggerBody()?[‘ID’]}”,

          “notificationType”: “Email”,

          “enableActionableMessages”: true

        },

        “authentication”: {

          “type”: “Raw”,

          “scheme”: “Key”,

          “parameter”: “$connections[‘shared_approvals’][‘connectionId’]”

        }

      },

      “runAfter”: {

        “Initialize_approver_email”: [“Succeeded”]

      }

    },

    “Send_Teams_approval_notification”: {

      “type”: “ApiConnection”,

      “inputs”: {

        “host”: {

          “connectionName”: “shared_teams”,

          “operationId”: “PostMessageToChannel”

        },

        “parameters”: {

          “team”: “YOUR_TEAM_ID”,

          “channel”: “YOUR_CHANNEL_ID”,

          “message”: “**New Azure Subscription Request**\n- Project: @{triggerBody()?[‘Title’]}\n- Requester: @{triggerBody()?[‘RequesterEmail’]}\n- Landing Zone: @{triggerBody()?[‘LandingZoneType’]}\n- Est. cost: @{triggerBody()?[‘ExpectedMonthlySpend’]}\n\n[Approve or Reject in Outlook]”

        },

        “authentication”: {

          “type”: “Raw”,

          “scheme”: “Key”,

          “parameter”: “$connections[‘shared_teams’][‘connectionId’]”

        }

      },

      “runAfter”: {

        “Send_approval_email”: [“Succeeded”]

      }

    },

    “Condition_approval_outcome”: {

      “type”: “If”,

      “expression”: {

        “equals”: [

          “@body(‘Send_approval_email’)?[‘result’]?[‘outcome’]”,

          “Approve”

        ]

      },

      “actions”: {

        “Update_SharePoint_status_approved”: {

          “type”: “ApiConnection”,

          “inputs”: {

            “host”: {

              “connectionName”: “shared_sharepointonline”,

              “operationId”: “UpdateItem”

            },

            “parameters”: {

              “siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,

              “listName”: “Subscription Requests”,

              “id”: “@triggerBody()?[‘ID’]”,

              “item”: {

                “Status”: “Approved”

              }

            },

            “authentication”: {

              “type”: “Raw”,

              “scheme”: “Key”,

              “parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”

            }

          },

          “runAfter”: {}

        },

        “Create_audit_log_approved”: {

          “type”: “ApiConnection”,

          “inputs”: {

            “host”: {

              “connectionName”: “shared_sharepointonline”,

              “operationId”: “CreateItem”

            },

            “parameters”: {

              “siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,

              “listName”: “Subscription Vending Log”,

              “item”: {

                “Title”: “Request @{triggerBody()?[‘ID’]} – Approved”,

                “RequestID”: “@{triggerBody()?[‘ID’]}”,

                “RequestTitle”: “@{triggerBody()?[‘Title’]}”,

                “Action”: “Approved”,

                “Actor”: “@{body(‘Send_approval_email’)?[‘responder’]?[’email’]}”,

                “Timestamp”: “@{utcNow()}”,

                “Comments”: “@{body(‘Send_approval_email’)?[‘result’]?[‘comments’]}”,

                “StatusBefore”: “Submitted”,

                “StatusAfter”: “Approved”

              }

            },

            “authentication”: {

              “type”: “Raw”,

              “scheme”: “Key”,

              “parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”

            }

          },

          “runAfter”: {

            “Update_SharePoint_status_approved”: [“Succeeded”]

          }

        },

        “Send_email_to_IT_shared_mailbox”: {

          “type”: “ApiConnection”,

          “inputs”: {

            “host”: {

              “connectionName”: “shared_outlook”,

              “operationId”: “SendEmail”

            },

            “parameters”: {

              “emailMessage”: {

                “To”: “it-team@yourcompany.com”,

                “Cc”: “@{triggerBody()?[‘RequesterEmail’]}”,

                “Subject”: “ACTION REQUIRED: Provision Azure subscription – @{triggerBody()?[‘Title’]}”,

                “Body”: “A subscription request has been approved. Please provision manually.\n\n**Request Details:**\n- Request ID: @{triggerBody()?[‘ID’]}\n- Project: @{triggerBody()?[‘Title’]}\n- Requester: @{triggerBody()?[‘RequesterEmail’]}\n- Landing Zone Type: @{triggerBody()?[‘LandingZoneType’]}\n- Environment: @{triggerBody()?[‘EnvironmentPurpose’]}\n- Primary Region: @{triggerBody()?[‘PrimaryRegion’]}\n- Subscription Alias: @{triggerBody()?[‘SubscriptionAlias’]}\n- Subscription Owners: @{triggerBody()?[‘SubscriptionOwners’]}\n- Additional Contributors: @{triggerBody()?[‘AdditionalContributors’]}\n- Expected Monthly Spend: @{triggerBody()?[‘ExpectedMonthlySpend’]}\n- Resource Providers: @{triggerBody()?[‘ResourceProviders’]}\n- Network Requirements: @{triggerBody()?[‘NetworkRequirements’]}\n- Additional Policies: @{triggerBody()?[‘AdditionalPolicies’]}\n- Start Date: @{triggerBody()?[‘StartDate’]}\n- End Date: @{triggerBody()?[‘EndDate’]}\n\n**SharePoint Link:** @{body(‘Send_approval_email’)?[‘itemLink’]}\n\nAfter provisioning, please update the SharePoint item with the Subscription ID and change status to ‘Provisioned’.”

              }

            },

            “authentication”: {

              “type”: “Raw”,

              “scheme”: “Key”,

              “parameter”: “$connections[‘shared_outlook’][‘connectionId’]”

            }

          },

          “runAfter”: {

            “Create_audit_log_approved”: [“Succeeded”]

          }

        },

        “Create_audit_log_handoff”: {

          “type”: “ApiConnection”,

          “inputs”: {

            “host”: {

              “connectionName”: “shared_sharepointonline”,

              “operationId”: “CreateItem”

            },

            “parameters”: {

              “siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,

              “listName”: “Subscription Vending Log”,

              “item”: {

                “Title”: “Request @{triggerBody()?[‘ID’]} – Handed off to IT”,

                “RequestID”: “@{triggerBody()?[‘ID’]}”,

                “RequestTitle”: “@{triggerBody()?[‘Title’]}”,

                “Action”: “Handed off to IT”,

                “Actor”: “System”,

                “Timestamp”: “@{utcNow()}”,

                “Comments”: “Email sent to IT shared mailbox for manual provisioning”,

                “StatusBefore”: “Approved”,

                “StatusAfter”: “Handed off”

              }

            },

            “authentication”: {

              “type”: “Raw”,

              “scheme”: “Key”,

              “parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”

            }

          },

          “runAfter”: {

            “Send_email_to_IT_shared_mailbox”: [“Succeeded”]

          }

        },

        “Send_approval_notification_to_requester”: {

          “type”: “ApiConnection”,

          “inputs”: {

            “host”: {

              “connectionName”: “shared_outlook”,

              “operationId”: “SendEmail”

            },

            “parameters”: {

              “emailMessage”: {

                “To”: “@{triggerBody()?[‘RequesterEmail’]}”,

                “Subject”: “Your Azure subscription request has been approved”,

                “Body”: “Dear @{triggerBody()?[‘Title’]},\n\nYour request for a new Azure subscription has been **approved**.\n\nThe IT team has been notified and will provision the subscription manually. You will receive another email when it is ready.\n\n**Request ID:** @{triggerBody()?[‘ID’]}\n**Subscription Alias:** @{triggerBody()?[‘SubscriptionAlias’]}\n\nEstimated provisioning time: 1-2 business days.\n\nThank you.”

              }

            },

            “authentication”: {

              “type”: “Raw”,

              “scheme”: “Key”,

              “parameter”: “$connections[‘shared_outlook’][‘connectionId’]”

            }

          },

          “runAfter”: {

            “Create_audit_log_handoff”: [“Succeeded”]

          }

        }

      },

      “else”: {

        “actions”: {

          “Update_SharePoint_status_rejected”: {

            “type”: “ApiConnection”,

            “inputs”: {

              “host”: {

                “connectionName”: “shared_sharepointonline”,

                “operationId”: “UpdateItem”

              },

              “parameters”: {

                “siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,

                “listName”: “Subscription Requests”,

                “id”: “@triggerBody()?[‘ID’]”,

                “item”: {

                  “Status”: “Rejected”,

                  “ApproverComment”: “@{body(‘Send_approval_email’)?[‘result’]?[‘comments’]}”

                }

              },

              “authentication”: {

                “type”: “Raw”,

                “scheme”: “Key”,

                “parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”

              }

            },

            “runAfter”: {}

          },

          “Create_audit_log_rejected”: {

            “type”: “ApiConnection”,

            “inputs”: {

              “host”: {

                “connectionName”: “shared_sharepointonline”,

                “operationId”: “CreateItem”

              },

              “parameters”: {

                “siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,

                “listName”: “Subscription Vending Log”,

                “item”: {

                  “Title”: “Request @{triggerBody()?[‘ID’]} – Rejected”,

                  “RequestID”: “@{triggerBody()?[‘ID’]}”,

                  “RequestTitle”: “@{triggerBody()?[‘Title’]}”,

                  “Action”: “Rejected”,

                  “Actor”: “@{body(‘Send_approval_email’)?[‘responder’]?[’email’]}”,

                  “Timestamp”: “@{utcNow()}”,

                  “Comments”: “@{body(‘Send_approval_email’)?[‘result’]?[‘comments’]}”,

                  “StatusBefore”: “Submitted”,

                  “StatusAfter”: “Rejected”

                }

              },

              “authentication”: {

                “type”: “Raw”,

                “scheme”: “Key”,

                “parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”

              }

            },

            “runAfter”: {

              “Update_SharePoint_status_rejected”: [“Succeeded”]

            }

          },

          “Send_rejection_email_to_requester”: {

            “type”: “ApiConnection”,

            “inputs”: {

              “host”: {

                “connectionName”: “shared_outlook”,

                “operationId”: “SendEmail”

              },

              “parameters”: {

                “emailMessage”: {

                  “To”: “@{triggerBody()?[‘RequesterEmail’]}”,

                  “Subject”: “Your Azure subscription request was not approved”,

                  “Body”: “Dear @{triggerBody()?[‘Title’]},\n\nYour request for a new Azure subscription has been **rejected** by the approver.\n\n**Reason:** @{body(‘Send_approval_email’)?[‘result’]?[‘comments’]}\n\nIf you believe this is an error, please contact the Cloud Center of Excellence.”

                }

              },

              “authentication”: {

                “type”: “Raw”,

                “scheme”: “Key”,

                “parameter”: “$connections[‘shared_outlook’][‘connectionId’]”

              }

            },

            “runAfter”: {

              “Create_audit_log_rejected”: [“Succeeded”]

            }

          }

        }

      },

      “runAfter”: {

        “Send_Teams_approval_notification”: [“Succeeded”]

      }

    }

  },

  “outputs”: {}

}

Key Differences from the Azure DevOps Version

Feature

DevOps Version

Email Handoff Version

Provisioning trigger

HTTP call to Azure DevOps pipeline

Email to IT shared mailbox

Status after approval

ProvisioningStarted → Provisioned

Approved → Handed off to IT

Final user notification

“Your subscription is ready (with ID)”

“Approved, IT will provision manually”

Audit log entries

ProvisioningStarted, Provisioned

Handed off to IT

Complexity

High (requires PAT, pipeline, polling)

Low (just email)

Placeholders to Replace

Placeholder

Example

YOUR_SHAREPOINT_SITE_URL

https://contoso.sharepoint.com/sites/AzureSubscriptionVending

cceo@yourcompany.com

cloud-governance@contoso.com

it-team@yourcompany.com

azure-provisioning@contoso.com

YOUR_TEAM_ID / YOUR_CHANNEL_ID (optional)

Teams channel ID (or remove the Teams action if not needed)

What IT Needs to Do Manually

When IT receives the email, they will:

  1. Create a new subscription using EA portal / Azure Billing API
  2. Move it to the correct management group
  3. Assign RBAC roles (Owner, Contributor)
  4. Apply policies, budget alerts, and register resource providers
  5. Configure VNet peering if requested
  6. Update the SharePoint list item: add SubscriptionID, change Status to Provisioned
  7. Notify the requester (or the flow can be extended to detect the status change and send a final email)

Optional enhancement: Create a second Power Automate flow that triggers when a list item is modified (status changes to Provisioned) and then sends the “ready” email to the requester. That keeps the manual step but automates the final notification.

Testing Checklist

  • SharePoint lists (Subscription Requests, Subscription Vending Log) exist
  • Flow connections reconfigured (SharePoint, Approvals, Outlook, Teams optional)
  • Approver email address is correct
  • IT shared mailbox is correct
  • Submit a test request → Approver gets email → Click Approve → IT receives email
  • Audit log shows: Submitted → Approved → Handed off to IT
  • Requester receives “approved” email

Let me know if you want me to provide the second flow that watches for Provisioned status and sends the final “ready” email automatically when IT updates the item.

yes

We need to provide the second flow that watches for when IT updates the SharePoint list item status to “Provisioned” and then sends the final “ready” email to the requester. This will be a separate Power Automate flow (trigger: when an item is modified). Include the JSON export for that flow as well.

Here is the second Power Automate flow that watches for when IT updates the SharePoint list item status to Provisioned and then automatically sends the final “ready” email to the requester.

Flow Overview – Final Notification after IT Provisioning

text

IT manually provisions subscription (outside of flow)

       ↓

IT updates SharePoint list item:

   – Status = “Provisioned”

   – SubscriptionID = <actual ID>

       ↓

Flow trigger: When an item is modified (only if Status changed to Provisioned)

       ↓

Get item details

       ↓

Check if Status is “Provisioned” AND previous status was not Provisioned (avoid loops)

       ↓

Send final “ready” email to requester with Subscription ID

       ↓

Update audit log: “Provisioned” entry (if not already logged)

This flow runs independently of the approval flow and completes the user journey.

How to Import

  1. Copy the JSON below into a file named SubscriptionProvisionedNotification_Flow.json
  2. In Power Automate → My flows → Import → Select file → upload
  3. Reconfigure connections: SharePoint, Outlook
  4. Replace placeholder YOUR_SHAREPOINT_SITE_URL
  5. Turn on the flow

Flow Definition JSON (Final Notification on Provisioned Status)

json

{

  “$schema”: “https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#”,

  “contentVersion”: “1.0.0.0”,

  “parameters”: {

    “$connections”: {

      “defaultValue”: {},

      “type”: “Object”

    }

  },

  “triggers”: {

    “When_an_item_is_modified”: {

      “type”: “ApiConnection”,

      “inputs”: {

        “host”: {

          “connectionName”: “shared_sharepointonline”,

          “operationId”: “WhenItemModified”

        },

        “parameters”: {

          “siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,

          “listName”: “Subscription Requests”

        },

        “authentication”: {

          “type”: “Raw”,

          “scheme”: “Key”,

          “parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”

        }

      },

      “recurrence”: {

        “frequency”: “Second”,

        “interval”: 60

      },

      “splitOn”: “@triggerBody()?[‘value’]”

    }

  },

  “actions”: {

    “Get_item_details”: {

      “type”: “ApiConnection”,

      “inputs”: {

        “host”: {

          “connectionName”: “shared_sharepointonline”,

          “operationId”: “GetItem”

        },

        “parameters”: {

          “siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,

          “listName”: “Subscription Requests”,

          “id”: “@triggerBody()?[‘ID’]”

        },

        “authentication”: {

          “type”: “Raw”,

          “scheme”: “Key”,

          “parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”

        }

      },

      “runAfter”: {}

    },

    “Condition_status_is_provisioned”: {

      “type”: “If”,

      “expression”: {

        “equals”: [

          “@triggerBody()?[‘Status’]”,

          “Provisioned”

        ]

      },

      “actions”: {

        “Check_previous_status_not_provisioned”: {

          “type”: “If”,

          “expression”: {

            “not”: {

              “equals”: [

                “@{triggerBody()?[‘Status’]}”,

                “@{triggerBody()?[‘PreviousStatus’]}”

              ]

            }

          },

          “actions”: {

            “Send_final_ready_email”: {

              “type”: “ApiConnection”,

              “inputs”: {

                “host”: {

                  “connectionName”: “shared_outlook”,

                  “operationId”: “SendEmail”

                },

                “parameters”: {

                  “emailMessage”: {

                    “To”: “@{triggerBody()?[‘RequesterEmail’]}”,

                    “Subject”: “Your Azure subscription is ready for use”,

                    “Body”: “Dear @{triggerBody()?[‘Title’]},\n\nYour requested Azure subscription has been **provisioned successfully** by the IT team.\n\n**Subscription ID:** @{triggerBody()?[‘SubscriptionID’]}\n**Landing Zone Type:** @{triggerBody()?[‘LandingZoneType’]}\n**Environment:** @{triggerBody()?[‘EnvironmentPurpose’]}\n\nYou can now access it in the Azure portal: https://portal.azure.com\n\n**Next steps:**\n- Ensure you have the required RBAC roles (Owner/Contributor as requested).\n- Review the assigned Azure policies and budget alerts.\n- Start deploying your workloads.\n\nRequest ID: @{triggerBody()?[‘ID’]}\n\nThank you for using the Subscription Vending service.”

                  }

                },

                “authentication”: {

                  “type”: “Raw”,

                  “scheme”: “Key”,

                  “parameter”: “$connections[‘shared_outlook’][‘connectionId’]”

                }

              },

              “runAfter”: {}

            },

            “Create_audit_log_provisioned”: {

              “type”: “ApiConnection”,

              “inputs”: {

                “host”: {

                  “connectionName”: “shared_sharepointonline”,

                  “operationId”: “CreateItem”

                },

                “parameters”: {

                  “siteAddress”: “YOUR_SHAREPOINT_SITE_URL”,

                  “listName”: “Subscription Vending Log”,

                  “item”: {

                    “Title”: “Request @{triggerBody()?[‘ID’]} – Provisioned”,

                    “RequestID”: “@{triggerBody()?[‘ID’]}”,

                    “RequestTitle”: “@{triggerBody()?[‘Title’]}”,

                    “Action”: “Provisioned”,

                    “Actor”: “IT Team (manual)”,

                    “Timestamp”: “@{utcNow()}”,

                    “Comments”: “Subscription ID: @{triggerBody()?[‘SubscriptionID’]}”,

                    “StatusBefore”: “@{triggerBody()?[‘Status’]}”,

                    “StatusAfter”: “Provisioned”

                  }

                },

                “authentication”: {

                  “type”: “Raw”,

                  “scheme”: “Key”,

                  “parameter”: “$connections[‘shared_sharepointonline’][‘connectionId’]”

                }

              },

              “runAfter”: {

                “Send_final_ready_email”: [“Succeeded”]

              }

            }

          },

          “runAfter”: {}

        }

      },

      “runAfter”: {

        “Get_item_details”: [“Succeeded”]

      }

    }

  },

  “outputs”: {}

}

Important Notes

Trigger Considerations

  • The trigger When an item is modified will fire for any change to the list item.
  • The condition Status == “Provisioned” ensures we only proceed when status changes to Provisioned.
  • The nested condition PreviousStatus != Status prevents re-triggering if IT saves the same status again. (Note: The trigger body includes a PreviousStatus property automatically for SharePoint list modifications.)

Audit Log

  • This flow creates a Provisioned entry in the audit log. If your approval flow already created a Handed off to IT entry, this adds the final Provisioned entry.
  • If you want a single Provisioned entry, you can disable the audit log creation in this flow and rely on IT manually adding it when they update the status. The JSON above includes it for completeness.

IT Workflow Integration

  • IT receives the handoff email from the approval flow.
  • After manually provisioning, IT updates the SharePoint list item:
    • Change Status dropdown to Provisioned
    • Fill in SubscriptionID column
    • (Optional) Add a comment in ApproverComment or a separate ITNotes column
  • This flow then sends the final email automatically.

Optional Enhancement: Email IT if Provisioning Fails

If IT needs to mark a request as failed, add another condition in this flow (or a separate flow) that watches for Status == “ProvisioningFailed” and sends an alert to both requester and CCoE.

Testing Checklist for This Flow

  • SharePoint list Subscription Requests exists with columns Status, SubscriptionID, RequesterEmail, Title, LandingZoneType, EnvironmentPurpose
  • Flow imported and connections reconfigured (SharePoint, Outlook)
  • Placeholder YOUR_SHAREPOINT_SITE_URL replaced
  • Existing request is in Approved or Handed off to IT status
  • Manually edit the list item: change Status to Provisioned, add a dummy SubscriptionID
  • Verify the requester receives the final “ready” email
  • Check audit log for new Provisioned entry

End-to-End Flow Summary (Both Flows Combined)

Step

Flow

Trigger

Action

1

Approval flow

Item created in SharePoint

Send approval email

2

Approval flow

Approver clicks Approve

Email IT shared mailbox, notify requester

3

(Manual)

IT provisions subscription

IT updates SharePoint: Status = Provisioned

4

Notification flow

Item modified (Status = Provisioned)

Send final “ready” email to requester

Now you have a complete, low‑code solution for Azure Subscription Vending using SharePoint + Power Automate + email handoff to IT, with full audit logging and final user notification.

Let me know if you want the flows packaged as a single importable solution (using Power Platform Solution export) or if you need help with the SharePoint list templates (schema JSON for list creation via PnP PowerShell).

show me the power platform solution export and hlep with sharepoint list templates

The user is asking for two things: a Power Platform solution export and help with SharePoint list templates. This is a follow-up to a previous conversation where we provided Power Automate flow JSONs for subscription vending and W365 workflows. Now they want to package these as a Power Platform solution and get SharePoint list templates (likely as XML or JSON for PnP PowerShell).

I need to search for the most up-to-date documentation and methods for creating Power Platform solutions and SharePoint list templates.

I’ll search for “Power Platform solution export unmanaged 2026” and “SharePoint list template PnP PowerShell schema”.

Found 20 web pages

The search results for Power Platform solutions show relevant links, but they are mostly about CLI and DevOps, not a simple “export package” feature. For SharePoint list templates, the results show methods using PnP PowerShell and XML schemas.

To provide comprehensive help, I need to open several of these results to gather detailed information.

Read 4 pages

Microsoft Power Platform CLI solution command group – Power Platform

【SharePointリスト作成】 Excel 定義から SharePoint リストを一括作成する方法 #0225|Shinichi Kawara

SharePointのリストをPowerShellで他のサイトに移行する

How to Create a Custom List Template in SharePoint Online (2026)

The search results provide a good foundation. The Power Platform CLI documentation shows the pac solution export command. The PnP provisioning XML method is detailed in the Japanese article, which includes a PowerShell script to generate the XML from a CSV. The other article shows how to export a list template using Get-PnPSiteTemplate. The “mrsharepoint.com” article shows how to use Get-SPOSiteScriptFromList.

I need to provide a comprehensive answer covering Power Platform solution export and SharePoint list templates. I’ll structure the answer with two main parts: Part 1 for Power Platform solution export and Part 2 for SharePoint list templates. I’ll include step-by-step instructions, code examples, and best practices.

I’ll show you how to create a reusable Power Platform solution containing the Power Automate flows, along with the SharePoint list templates for the request form and audit log.

🗃️ Part 1: SharePoint List Templates

You can deploy the required lists quickly using PnP PowerShell. This method is ideal for source-controlling your list structures (schema and columns).

Here are the complete templates for your two lists.

  1. Main Request List: Subscription Requests

This template includes all the columns we defined earlier.

xml

<pnp:Provisioning xmlns:pnp=”http://schemas.dev.office.com/PnP/2016/05/ProvisioningSchema”>

  <pnp:Preferences Generator=”PnP PowerShell” />

  <pnp:Templates>

    <pnp:ProvisioningTemplate ID=”SubscriptionRequests”>

      <pnp:Lists>

        <pnp:ListInstance Title=”Subscription Requests” Description=”Azure subscription requests from users” TemplateType=”100″ Url=”Lists/SubscriptionRequests”>

          <pnp:ContentTypeBindings>

            <pnp:ContentTypeBinding ContentTypeID=”0x01″ Default=”true” />

          </pnp:ContentTypeBindings>

          <pnp:Fields>

            <!– Requester Information –>

            <Field Type=”Text” Name=”RequesterEmail” DisplayName=”Requester Email” Required=”TRUE” />

            <Field Type=”Text” Name=”CostCenter” DisplayName=”Cost Center” Required=”TRUE” />

            <Field Type=”Note” Name=”Justification” DisplayName=”Business Justification” Required=”TRUE” RichText=”FALSE” NumLines=”6″ />

           

            <!– Subscription Configuration –>

            <Field Type=”Choice” Name=”LandingZoneType” DisplayName=”Landing Zone Type” Required=”TRUE”>

              <CHOICES>

                <CHOICE>Corp (connected to on-prem)</CHOICE>

                <CHOICE>Online (internet-facing)</CHOICE>

                <CHOICE>Sandbox (no production)</CHOICE>

              </CHOICES>

            </Field>

            <Field Type=”Choice” Name=”EnvironmentPurpose” DisplayName=”Environment Purpose” Required=”TRUE”>

              <CHOICES>

                <CHOICE>Development/Test</CHOICE>

                <CHOICE>Production</CHOICE>

                <CHOICE>Shared Services</CHOICE>

                <CHOICE>Disaster Recovery</CHOICE>

              </CHOICES>

            </Field>

            <Field Type=”Choice” Name=”PrimaryRegion” DisplayName=”Primary Azure Region” Required=”TRUE”>

              <CHOICES>

                <CHOICE>East US</CHOICE>

                <CHOICE>West Europe</CHOICE>

                <CHOICE>Southeast Asia</CHOICE>

              </CHOICES>

            </Field>

            <Field Type=”Choice” Name=”SecondaryRegion” DisplayName=”Secondary Region (DR)”>

              <CHOICES>

                <CHOICE>None</CHOICE>

                <CHOICE>West US</CHOICE>

                <CHOICE>North Europe</CHOICE>

              </CHOICES>

            </Field>

            <Field Type=”Currency” Name=”ExpectedMonthlySpend” DisplayName=”Expected Monthly Spend (USD)” Required=”TRUE” />

            <Field Type=”Text” Name=”SubscriptionAlias” DisplayName=”Subscription Alias” Required=”TRUE” />

            <Field Type=”Text” Name=”SubscriptionOwners” DisplayName=”Subscription Owner(s) (emails)” Required=”TRUE” />

            <Field Type=”Text” Name=”AdditionalContributors” DisplayName=”Additional Contributor(s) (emails)” />

            <Field Type=”MultiChoice” Name=”ResourceProviders” DisplayName=”Requested Resource Providers”>

              <CHOICES>

                <CHOICE>Microsoft.Compute</CHOICE>

                <CHOICE>Microsoft.ContainerService</CHOICE>

                <CHOICE>Microsoft.Sql</CHOICE>

                <CHOICE>Microsoft.Storage</CHOICE>

              </CHOICES>

            </Field>

           

            <!– Networking & Policies –>

            <Field Type=”Choice” Name=”NetworkRequirements” DisplayName=”Network Requirements” Required=”TRUE”>

              <CHOICES>

                <CHOICE>VNet peering to hub</CHOICE>

                <CHOICE>Direct on-prem connectivity</CHOICE>

                <CHOICE>No connectivity needed (isolated)</CHOICE>

              </CHOICES>

            </Field>

            <Field Type=”MultiChoice” Name=”AdditionalPolicies” DisplayName=”Additional Azure Policies”>

              <CHOICES>

                <CHOICE>Deny public IPs</CHOICE>

                <CHOICE>Enforce tags</CHOICE>

                <CHOICE>Encrypt disks</CHOICE>

              </CHOICES>

            </Field>

           

            <!– Dates –>

            <Field Type=”DateTime” Name=”StartDate” DisplayName=”Start Date” Required=”TRUE” Format=”DateOnly” />

            <Field Type=”DateTime” Name=”EndDate” DisplayName=”End Date (if temporary)” Format=”DateOnly” />

           

            <!– Status & Output –>

            <Field Type=”Choice” Name=”Status” DisplayName=”Status”>

              <CHOICES>

                <CHOICE>Submitted</CHOICE>

                <CHOICE>Approved</CHOICE>

                <CHOICE>Provisioned</CHOICE>

                <CHOICE>Rejected</CHOICE>

              </CHOICES>

              <Default>Submitted</Default>

            </Field>

            <Field Type=”Text” Name=”SubscriptionID” DisplayName=”Subscription ID” />

            <Field Type=”Note” Name=”ApproverComment” DisplayName=”Approver Comment” RichText=”FALSE” />

          </pnp:Fields>

          <pnp:Views>

            <View Name=”All Items” DefaultView=”TRUE” />

          </pnp:Views>

        </pnp:ListInstance>

      </pnp:Lists>

    </pnp:ProvisioningTemplate>

  </pnp:Templates>

</pnp:Provisioning>

  1. Audit Log List: Subscription Vending Log

This list records every action for complete traceability.

xml

<pnp:Provisioning xmlns:pnp=”http://schemas.dev.office.com/PnP/2016/05/ProvisioningSchema”>

  <pnp:Preferences Generator=”PnP PowerShell” />

  <pnp:Templates>

    <pnp:ProvisioningTemplate ID=”SubscriptionVendingLog”>

      <pnp:Lists>

        <pnp:ListInstance Title=”Subscription Vending Log” Description=”Audit trail for subscription requests” TemplateType=”100″ Url=”Lists/SubscriptionVendingLog”>

          <pnp:ContentTypeBindings>

            <pnp:ContentTypeBinding ContentTypeID=”0x01″ Default=”true” />

          </pnp:ContentTypeBindings>

          <pnp:Fields>

            <Field Type=”Number” Name=”RequestID” DisplayName=”Request ID” Required=”TRUE” />

            <Field Type=”Text” Name=”RequestTitle” DisplayName=”Request Title” Required=”TRUE” />

            <Field Type=”Choice” Name=”Action” DisplayName=”Action” Required=”TRUE”>

              <CHOICES>

                <CHOICE>Submitted</CHOICE>

                <CHOICE>Approved</CHOICE>

                <CHOICE>Handed off to IT</CHOICE>

                <CHOICE>Provisioned</CHOICE>

                <CHOICE>Rejected</CHOICE>

              </CHOICES>

            </Field>

            <Field Type=”Text” Name=”Actor” DisplayName=”Actor (Email)” Required=”TRUE” />

            <Field Type=”DateTime” Name=”Timestamp” DisplayName=”Timestamp” Required=”TRUE” Format=”DateTime” />

            <Field Type=”Note” Name=”Comments” DisplayName=”Comments” RichText=”FALSE” />

            <Field Type=”Text” Name=”StatusBefore” DisplayName=”Status Before” />

            <Field Type=”Text” Name=”StatusAfter” DisplayName=”Status After” />

          </pnp:Fields>

          <pnp:Views>

            <View Name=”All Items” DefaultView=”TRUE”>

              <ViewFields>

                <FieldRef Name=”RequestID” />

                <FieldRef Name=”Action” />

                <FieldRef Name=”Actor” />

                <FieldRef Name=”Timestamp” />

                <FieldRef Name=”Comments” />

              </ViewFields>

              <RowLimit>100</RowLimit>

              <Query>

                <OrderBy>

                  <FieldRef Name=”Timestamp” Ascending=”FALSE” />

                </OrderBy>

              </Query>

            </View>

          </pnp:Views>

        </pnp:ListInstance>

      </pnp:Lists>

    </pnp:ProvisioningTemplate>

  </pnp:Templates>

</pnp:Provisioning>

  1. How to Deploy the SharePoint Lists Using PnP PowerShell

Follow these steps to apply the XML templates above to your SharePoint site.

  1. Install PnP PowerShell Module (if not already installed):

powershell

Install-Module -Name PnP.PowerShell -Scope CurrentUser

  1. Connect to your SharePoint site:

powershell

Connect-PnPOnline -Url “https://yourtenant.sharepoint.com/sites/AzureSubscriptionVending” -Interactive

  1. Apply the first list template:

powershell

Invoke-PnPSiteTemplate -Path “C:\path\to\SubscriptionRequestsTemplate.xml”

  1. Apply the second list template:

powershell

Invoke-PnPSiteTemplate -Path “C:\path\to\SubscriptionVendingLogTemplate.xml”

💡 Pro Tip: If you prefer a CSV-driven approach to generate the XML automatically (ideal for source control), you can use a script like the one described in the PnP provisioning guide.

🧩 Part 2: Power Platform Solution Export

To package the Power Automate flows, SharePoint connection references, and other components into a single reusable unit, you need to create a Power Platform Solution.

⚠️ Important: You can only export unmanaged solutions from a development environment. Managed solutions are for production deployment and cannot be edited.

Step 1: Create a New Solution in Power Apps Maker Portal

  1. Navigate to Power Apps Maker Portal → Solutions → New solution
  2. Enter details:
    • Display name: Azure Subscription Vending
    • Publisher: Select the default or create a custom one
    • Version: 1.0.0.0

Step 2: Add Components to Your Solution

Add all related artifacts to your solution:

Component Type

Components to Include

Cloud flow

Subscription Vending – Approval & Handoff
Subscription Provisioned – Final Notification

Connection reference

SharePoint connection, Outlook connection, Approvals connection, Teams connection (auto-created when adding flows)

SharePoint site URL (if using environment variables)

Variable for the target SharePoint site

How to add:

  • Open your solution → Add existing → Cloud flow → Select your flows
  • The system will automatically include required connection references.

Step 3: Export the Solution

Option A: Manual Export via Maker Portal (Simpler)

  1. In your solution, select Export from the top menu
  2. Choose Unmanaged (for development or source control)
  3. Download the .zip file

Option B: Automated Export via Power Platform CLI (For CI/CD)
This method is ideal for DevOps pipelines.

bash

pac solution export –name “AzureSubscriptionVending” –path “C:\exports” –managed false

For full automation in Azure DevOps pipelines, refer to the Power Platform Build Tools documentation.

Step 4: Import the Solution to Another Environment

  1. In the target environment, go to Solutions → Import
  2. Upload the .zip file
  3. Configure any required connection references (point them to the appropriate SharePoint site, user accounts, etc.)
  4. Publish all customizations

🔄 Quick Reference: Flow vs. Solution Components

What You Built

In Solution

Manual Deployment

Approval Flow (JSON)

✅ Yes – packaged as a cloud flow

❌ Must paste JSON and recreate connections

Notification Flow (JSON)

✅ Yes – packaged as a cloud flow

❌ Must paste JSON and recreate connections

SharePoint List Schema

❌ Not included – deploy separately via PnP

✅ Use XML template above

Audit Log Schema

❌ Not included – deploy separately via PnP

✅ Use XML template above

Connection References

✅ Yes – included

❌ Must manually recreate

Note: SharePoint lists are not automatically included in the solution export. You should version control the XML templates alongside your solution .zip file for a complete, reproducible deployment.

📋 Recommended Deployment Workflow

  1. Run PnP PowerShell script to create both SharePoint lists using the XML templates above
  2. Import the Power Platform Solution (.zip file) into the target environment
  3. Update connection references to point to the newly created SharePoint lists
  4. Turn on both flows
  5. Test the end-to-end process

💾 Sample Solution Package Files

I cannot directly send a .zip file, but I have provided all the necessary components for you to build the solution manually:

  • Flow 1 JSON → SubscriptionVending_EmailHandoff.json (from previous answer)
  • Flow 2 JSON → SubscriptionProvisionedNotification_Flow.json (from previous answer)
  • SharePoint List 1 XML → SubscriptionRequestsTemplate.xml (included above)
  • SharePoint List 2 XML → SubscriptionVendingLogTemplate.xml (included above)
  • Power Platform Solution → Create via Maker Portal (steps above)

Let me know if you need me to provide the CSV-to-XML generation script for the SharePoint lists or help with setting up the connection references in your imported solution.

lastly, how can automate the capture of status of approval process back into a log in Sharepoint showing a historical list of when past approval dates, by whom, and new entries for what has been submitted and auto updated when it is approved

We need to answer the user’s final question: “lastly, how can automate the capture of status of approval process back into a log in Sharepoint showing a historical list of when past approval dates, by whom, and new entries for what has been submitted and auto updated when it is approved”

They want to know how to automate capturing approval status (dates, who approved, etc.) into a SharePoint log. The user has already been given the audit log approach earlier, but they are asking specifically for this automation. So we need to provide a concise answer focusing on the mechanism: using Power Automate to write log entries when an item is created (submitted) and when the approval outcome is received (approved/rejected). Include details like capturing approver email, timestamp, comments, and status changes. Also mention that the flow updates the log list automatically.

The answer should be practical, step-by-step, referencing the earlier flow examples but highlighting the log capture actions.

We’ll produce a final answer that directly addresses this question.

You can fully automate the capture of approval status into a SharePoint audit log using Power Automate triggered by actions on your request list. The log will record:

  • When the request was submitted, approved, or rejected (timestamp)
  • Who performed the action (requester or approver email)
  • What changed (status before/after, approval comments)

This is already embedded in the flows I provided, but here is a focused explanation of how to implement just the audit logging piece, assuming you have the SharePoint lists from the previous steps.

📝 How the Automated Audit Log Works

You need two triggers in Power Automate to capture everything:

  1. When an item is created – logs the submission
  2. When an approval completes – logs the approval or rejection (within the same flow)

Both write entries into a separate SharePoint list called Subscription Vending Log (or similar).

🧩 Step-by-Step: Add Audit Logging to Your Approval Flow

  1. Create the Log List (if not already done)

Use the SharePoint list template from the previous answer, or manually create a list with these columns:

Column

Type

Purpose

Title

Single line

Auto‑generated: Request [ID] – [Action]

RequestID

Number

ID of the original request

RequestTitle

Single line

Name of the request (project name)

Action

Choice

Submitted, Approved, Rejected, Provisioned

Actor

Single line

Email of who performed the action

Timestamp

Date/Time

Default = current time

Comments

Multiple lines

Justification (for submission) or approver’s reason

StatusBefore

Single line

Previous status of the request

StatusAfter

Single line

New status after the action

  1. Modify Your Power Automate Approval Flow

In the flow that handles the request (triggered when an item is created), add these Create item actions (targeting the log list).

  1. a) Log the submission – right after the trigger

text

When an item is created (SharePoint)

├─ Create item in “Subscription Vending Log”

   ├─ Title: “Request @{triggerBody()?[‘ID’]} – Submitted”

   ├─ RequestID: @{triggerBody()?[‘ID’]}

   ├─ RequestTitle: @{triggerBody()?[‘Title’]}

   ├─ Action: “Submitted”

   ├─ Actor: @{triggerBody()?[‘RequesterEmail’]}

   ├─ Timestamp: @{utcNow()}

   ├─ Comments: @{triggerBody()?[‘Justification’]}

   ├─ StatusBefore: (empty)

   └─ StatusAfter: “Submitted”

  1. b) Log the approval – inside the Approve branch

After the approval outcome is received and you update the main request status to Approved, add:

text

Create item in “Subscription Vending Log”

   ├─ Title: “Request @{triggerBody()?[‘ID’]} – Approved”

   ├─ RequestID: @{triggerBody()?[‘ID’]}

   ├─ RequestTitle: @{triggerBody()?[‘Title’]}

   ├─ Action: “Approved”

   ├─ Actor: @{body(‘Send_approval_email’)?[‘responder’]?[’email’]}

   ├─ Timestamp: @{utcNow()}

   ├─ Comments: @{body(‘Send_approval_email’)?[‘result’]?[‘comments’]}

   ├─ StatusBefore: “Submitted” (or “Pending Approval”)

   └─ StatusAfter: “Approved”

  1. c) Log the rejection – inside the Reject branch

Similarly, log the rejection with the approver’s comment.

🔁 Automatic Updates When Approved

Because the log entries are created immediately when the approval action occurs, the log list always reflects the current state without any manual intervention. You don’t need a separate flow to “update” the log; you simply append new entries as events happen.

The log becomes a chronological history of each request. To see all events for a single request, filter by RequestID.

📊 Example Log Output

After a request goes through submission → approval → provisioning, your log list will contain:

Title

Action

Actor

Timestamp

StatusBefore

StatusAfter

Request 5 – Submitted

Submitted

john@contoso.com

2025-03-15 10:00

 

Submitted

Request 5 – Approved

Approved

cceo@contoso.com

2025-03-15 11:30

Submitted

Approved

Request 5 – Provisioned

Provisioned

IT Team (manual)

2025-03-16 09:00

Approved

Provisioned

This gives you a full audit trail of when each action happened, by whom, and what changed.

🛠️ Minimal Power Automate Snippet (for a new flow)

If you want to start from scratch, here is a simplified JSON snippet that shows only the audit logging actions inside an approval flow (without the full subscription vending logic). You can insert this pattern into any approval flow.

json

“Create_log_submitted”: {

  “type”: “ApiConnection”,

  “inputs”: {

    “host”: { “connectionName”: “shared_sharepointonline” },

    “operationId”: “CreateItem”,

    “parameters”: {

      “siteAddress”: “YOUR_SITE_URL”,

      “listName”: “Subscription Vending Log”,

      “item”: {

        “Title”: “Request @{triggerBody()?[‘ID’]} – Submitted”,

        “RequestID”: “@{triggerBody()?[‘ID’]}”,

        “RequestTitle”: “@{triggerBody()?[‘Title’]}”,

        “Action”: “Submitted”,

        “Actor”: “@{triggerBody()?[‘RequesterEmail’]}”,

        “Timestamp”: “@{utcNow()}”,

        “StatusAfter”: “Submitted”

      }

    }

  }

},

“Create_log_approved”: {

  “type”: “ApiConnection”,

  “inputs”: {

    “host”: { “connectionName”: “shared_sharepointonline” },

    “operationId”: “CreateItem”,

    “parameters”: {

      “siteAddress”: “YOUR_SITE_URL”,

      “listName”: “Subscription Vending Log”,

      “item”: {

        “Title”: “Request @{triggerBody()?[‘ID’]} – Approved”,

        “RequestID”: “@{triggerBody()?[‘ID’]}”,

        “RequestTitle”: “@{triggerBody()?[‘Title’]}”,

        “Action”: “Approved”,

        “Actor”: “@{body(‘Send_approval_email’)?[‘responder’]?[’email’]}”,

        “Timestamp”: “@{utcNow()}”,

        “Comments”: “@{body(‘Send_approval_email’)?[‘result’]?[‘comments’]}”,

        “StatusBefore”: “Submitted”,

        “StatusAfter”: “Approved”

      }

    }

  }

}

✅ Summary

What you want to capture

How it is automated

When request was submitted

Flow logs on When an item is created

Who submitted it

RequesterEmail from the trigger

When it was approved

Flow logs inside the Approve branch of the approval action

Who approved it

responder[’email’] from the approval action

Any comments from approver

result[‘comments’] from the approval action

Status changes (before/after)

Hardcoded or dynamic values in log entry

The audit log is append‑only – no updates needed. Every state change creates a new row, giving you a complete, immutable history.

If you need the exact Power Automate flow JSON with all audit logging actions already inserted (for both the approval flow and the provisioning notification flow), just let me know and I will provide the merged, ready‑to‑import package.