> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.mercoa.com/embedded-ap-ar/guides/accounts-payable/approval-policies/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.mercoa.com/_mcp/server. ## [API Reference](/api-reference/entity/approval-policy) Approval Policies enable your users to set up an approval process for managing and paying any invoice they receive. ## Creating Approval Policies To create an Approval Policy: 1. [Create users](/common-concepts/entity-users) within an entity and optionally assign them roles. 2. Create the Approval Policy rule ## Creating Approval Policy rules Approval Policies can be created using the [API](/api-reference/entity/approval-policy/create) or through the [admin dashboard](https://mercoa.com/dashboard/payers) by clicking on the `Approval Policy` tab within an entity. Approval Policies consist of a trigger for the policy and a list of users that must approve the invoice. You can stack multiple Approval Policies on top of each other. ### Approval Policy Triggers The "Trigger" field allows you to select what conditions trigger this approval policy. You can select the following to trigger an approval policy: * Invoice Amounts (greater than) * Invoice Metadata * Invoice Vendors ### Number of Approvers Each approval policy can have a different number of approvers. You can set the number of approvers needed for each approval policy by using the "Number of Approvers" field. ### Approval Policy Rules The "Approval Policy Rules" field allows you to select which users are the approvers for this approval policy. You can select users based on their roles or by their user IDs. Roles are useful when you want any user with a specific role to be able to approve an invoice. User IDs are useful when you want to specify exactly which users can approve an invoice. ### Example Approval Policy In this example, we create an approval policy that triggers when an invoice is received and the invoice amount is greater than \$100. We set the number of approvers to 2 and let anyone with the "Controller" role or "Admin" role approve the invoice. ### Request POST [https://api.mercoa.com/entity/\{entityId}/approval-policy](https://api.mercoa.com/entity/\{entityId}/approval-policy) **`AlwaysTrigger`** ```curl AlwaysTrigger curl -X POST https://api.mercoa.com/entity/ent_8545a84e-a45f-41bf-bdf1-33b42a55812c/approval-policy \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "trigger": [], "rule": { "type": "approver", "identifierList": { "type": "userList", "value": [ "usr_8545a84e-a45f-41bf-bdf1-33b42a55812c", "usr_21661ac1-a2a8-4465-a6c0-64474ba8181d" ] }, "numApprovers": 2 }, "upstreamPolicyId": "root" }' ``` **`AlwaysTrigger`** ```python AlwaysTrigger import requests url = "https://api.mercoa.com/entity/ent_8545a84e-a45f-41bf-bdf1-33b42a55812c/approval-policy" payload = { "trigger": [], "rule": { "type": "approver", "identifierList": { "type": "userList", "value": ["usr_8545a84e-a45f-41bf-bdf1-33b42a55812c", "usr_21661ac1-a2a8-4465-a6c0-64474ba8181d"] }, "numApprovers": 2 }, "upstreamPolicyId": "root" } headers = { "Authorization": "Bearer ", "Content-Type": "application/json" } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` **`AlwaysTrigger`** ```typescript AlwaysTrigger import { MercoaClient } from "@mercoa/javascript"; const client = new MercoaClient({ token: "YOUR_TOKEN" }); await client.entity.approvalPolicy.create("ent_8545a84e-a45f-41bf-bdf1-33b42a55812c", { trigger: [], rule: { type: "approver", numApprovers: 2, identifierList: { type: "userList", value: ["usr_8545a84e-a45f-41bf-bdf1-33b42a55812c", "usr_21661ac1-a2a8-4465-a6c0-64474ba8181d"] } }, upstreamPolicyId: "root" }); ``` **`AlwaysTrigger`** ```go AlwaysTrigger package main import ( "fmt" "strings" "net/http" "io" ) func main() { url := "https://api.mercoa.com/entity/ent_8545a84e-a45f-41bf-bdf1-33b42a55812c/approval-policy" payload := strings.NewReader("{\n \"trigger\": [],\n \"rule\": {\n \"type\": \"approver\",\n \"identifierList\": {\n \"type\": \"userList\",\n \"value\": [\n \"usr_8545a84e-a45f-41bf-bdf1-33b42a55812c\",\n \"usr_21661ac1-a2a8-4465-a6c0-64474ba8181d\"\n ]\n },\n \"numApprovers\": 2\n },\n \"upstreamPolicyId\": \"root\"\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("Authorization", "Bearer ") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` **`AlwaysTrigger`** ```ruby AlwaysTrigger require 'uri' require 'net/http' url = URI("https://api.mercoa.com/entity/ent_8545a84e-a45f-41bf-bdf1-33b42a55812c/approval-policy") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Post.new(url) request["Authorization"] = 'Bearer ' request["Content-Type"] = 'application/json' request.body = "{\n \"trigger\": [],\n \"rule\": {\n \"type\": \"approver\",\n \"identifierList\": {\n \"type\": \"userList\",\n \"value\": [\n \"usr_8545a84e-a45f-41bf-bdf1-33b42a55812c\",\n \"usr_21661ac1-a2a8-4465-a6c0-64474ba8181d\"\n ]\n },\n \"numApprovers\": 2\n },\n \"upstreamPolicyId\": \"root\"\n}" response = http.request(request) puts response.read_body ``` **`AlwaysTrigger`** ```java AlwaysTrigger import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.post("https://api.mercoa.com/entity/ent_8545a84e-a45f-41bf-bdf1-33b42a55812c/approval-policy") .header("Authorization", "Bearer ") .header("Content-Type", "application/json") .body("{\n \"trigger\": [],\n \"rule\": {\n \"type\": \"approver\",\n \"identifierList\": {\n \"type\": \"userList\",\n \"value\": [\n \"usr_8545a84e-a45f-41bf-bdf1-33b42a55812c\",\n \"usr_21661ac1-a2a8-4465-a6c0-64474ba8181d\"\n ]\n },\n \"numApprovers\": 2\n },\n \"upstreamPolicyId\": \"root\"\n}") .asString(); ``` **`AlwaysTrigger`** ```php AlwaysTrigger request('POST', 'https://api.mercoa.com/entity/ent_8545a84e-a45f-41bf-bdf1-33b42a55812c/approval-policy', [ 'body' => '{ "trigger": [], "rule": { "type": "approver", "identifierList": { "type": "userList", "value": [ "usr_8545a84e-a45f-41bf-bdf1-33b42a55812c", "usr_21661ac1-a2a8-4465-a6c0-64474ba8181d" ] }, "numApprovers": 2 }, "upstreamPolicyId": "root" }', 'headers' => [ 'Authorization' => 'Bearer ', 'Content-Type' => 'application/json', ], ]); echo $response->getBody(); ``` **`AlwaysTrigger`** ```csharp AlwaysTrigger using RestSharp; var client = new RestClient("https://api.mercoa.com/entity/ent_8545a84e-a45f-41bf-bdf1-33b42a55812c/approval-policy"); var request = new RestRequest(Method.POST); request.AddHeader("Authorization", "Bearer "); request.AddHeader("Content-Type", "application/json"); request.AddParameter("application/json", "{\n \"trigger\": [],\n \"rule\": {\n \"type\": \"approver\",\n \"identifierList\": {\n \"type\": \"userList\",\n \"value\": [\n \"usr_8545a84e-a45f-41bf-bdf1-33b42a55812c\",\n \"usr_21661ac1-a2a8-4465-a6c0-64474ba8181d\"\n ]\n },\n \"numApprovers\": 2\n },\n \"upstreamPolicyId\": \"root\"\n}", ParameterType.RequestBody); IRestResponse response = client.Execute(request); ``` **`AlwaysTrigger`** ```swift AlwaysTrigger import Foundation let headers = [ "Authorization": "Bearer ", "Content-Type": "application/json" ] let parameters = [ "trigger": [], "rule": [ "type": "approver", "identifierList": [ "type": "userList", "value": ["usr_8545a84e-a45f-41bf-bdf1-33b42a55812c", "usr_21661ac1-a2a8-4465-a6c0-64474ba8181d"] ], "numApprovers": 2 ], "upstreamPolicyId": "root" ] as [String : Any] let postData = JSONSerialization.data(withJSONObject: parameters, options: []) let request = NSMutableURLRequest(url: NSURL(string: "https://api.mercoa.com/entity/ent_8545a84e-a45f-41bf-bdf1-33b42a55812c/approval-policy")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "POST" request.allHTTPHeaderFields = headers request.httpBody = postData as Data let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error as Any) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) } }) dataTask.resume() ``` ## Auto-Assign Approvers Approval policies can be set to automatically assign approvers when a user submits an invoice for approval. If the approval rule is set to `userList` and the number of approvers needed is equal to the number of users that are available to approve, it automatically assigns those users. ### Example ### Request POST [https://api.mercoa.com/entity/\{entityId}/approval-policy](https://api.mercoa.com/entity/\{entityId}/approval-policy) **`AlwaysTrigger`** ```curl AlwaysTrigger curl -X POST https://api.mercoa.com/entity/ent_8545a84e-a45f-41bf-bdf1-33b42a55812c/approval-policy \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "trigger": [], "rule": { "type": "approver", "identifierList": { "type": "userList", "value": [ "usr_8545a84e-a45f-41bf-bdf1-33b42a55812c", "usr_21661ac1-a2a8-4465-a6c0-64474ba8181d" ] }, "numApprovers": 2 }, "upstreamPolicyId": "root" }' ``` **`AlwaysTrigger`** ```python AlwaysTrigger import requests url = "https://api.mercoa.com/entity/ent_8545a84e-a45f-41bf-bdf1-33b42a55812c/approval-policy" payload = { "trigger": [], "rule": { "type": "approver", "identifierList": { "type": "userList", "value": ["usr_8545a84e-a45f-41bf-bdf1-33b42a55812c", "usr_21661ac1-a2a8-4465-a6c0-64474ba8181d"] }, "numApprovers": 2 }, "upstreamPolicyId": "root" } headers = { "Authorization": "Bearer ", "Content-Type": "application/json" } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` **`AlwaysTrigger`** ```typescript AlwaysTrigger import { MercoaClient } from "@mercoa/javascript"; const client = new MercoaClient({ token: "YOUR_TOKEN" }); await client.entity.approvalPolicy.create("ent_8545a84e-a45f-41bf-bdf1-33b42a55812c", { trigger: [], rule: { type: "approver", numApprovers: 2, identifierList: { type: "userList", value: ["usr_8545a84e-a45f-41bf-bdf1-33b42a55812c", "usr_21661ac1-a2a8-4465-a6c0-64474ba8181d"] } }, upstreamPolicyId: "root" }); ``` **`AlwaysTrigger`** ```go AlwaysTrigger package main import ( "fmt" "strings" "net/http" "io" ) func main() { url := "https://api.mercoa.com/entity/ent_8545a84e-a45f-41bf-bdf1-33b42a55812c/approval-policy" payload := strings.NewReader("{\n \"trigger\": [],\n \"rule\": {\n \"type\": \"approver\",\n \"identifierList\": {\n \"type\": \"userList\",\n \"value\": [\n \"usr_8545a84e-a45f-41bf-bdf1-33b42a55812c\",\n \"usr_21661ac1-a2a8-4465-a6c0-64474ba8181d\"\n ]\n },\n \"numApprovers\": 2\n },\n \"upstreamPolicyId\": \"root\"\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("Authorization", "Bearer ") req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` **`AlwaysTrigger`** ```ruby AlwaysTrigger require 'uri' require 'net/http' url = URI("https://api.mercoa.com/entity/ent_8545a84e-a45f-41bf-bdf1-33b42a55812c/approval-policy") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Post.new(url) request["Authorization"] = 'Bearer ' request["Content-Type"] = 'application/json' request.body = "{\n \"trigger\": [],\n \"rule\": {\n \"type\": \"approver\",\n \"identifierList\": {\n \"type\": \"userList\",\n \"value\": [\n \"usr_8545a84e-a45f-41bf-bdf1-33b42a55812c\",\n \"usr_21661ac1-a2a8-4465-a6c0-64474ba8181d\"\n ]\n },\n \"numApprovers\": 2\n },\n \"upstreamPolicyId\": \"root\"\n}" response = http.request(request) puts response.read_body ``` **`AlwaysTrigger`** ```java AlwaysTrigger import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.post("https://api.mercoa.com/entity/ent_8545a84e-a45f-41bf-bdf1-33b42a55812c/approval-policy") .header("Authorization", "Bearer ") .header("Content-Type", "application/json") .body("{\n \"trigger\": [],\n \"rule\": {\n \"type\": \"approver\",\n \"identifierList\": {\n \"type\": \"userList\",\n \"value\": [\n \"usr_8545a84e-a45f-41bf-bdf1-33b42a55812c\",\n \"usr_21661ac1-a2a8-4465-a6c0-64474ba8181d\"\n ]\n },\n \"numApprovers\": 2\n },\n \"upstreamPolicyId\": \"root\"\n}") .asString(); ``` **`AlwaysTrigger`** ```php AlwaysTrigger request('POST', 'https://api.mercoa.com/entity/ent_8545a84e-a45f-41bf-bdf1-33b42a55812c/approval-policy', [ 'body' => '{ "trigger": [], "rule": { "type": "approver", "identifierList": { "type": "userList", "value": [ "usr_8545a84e-a45f-41bf-bdf1-33b42a55812c", "usr_21661ac1-a2a8-4465-a6c0-64474ba8181d" ] }, "numApprovers": 2 }, "upstreamPolicyId": "root" }', 'headers' => [ 'Authorization' => 'Bearer ', 'Content-Type' => 'application/json', ], ]); echo $response->getBody(); ``` **`AlwaysTrigger`** ```csharp AlwaysTrigger using RestSharp; var client = new RestClient("https://api.mercoa.com/entity/ent_8545a84e-a45f-41bf-bdf1-33b42a55812c/approval-policy"); var request = new RestRequest(Method.POST); request.AddHeader("Authorization", "Bearer "); request.AddHeader("Content-Type", "application/json"); request.AddParameter("application/json", "{\n \"trigger\": [],\n \"rule\": {\n \"type\": \"approver\",\n \"identifierList\": {\n \"type\": \"userList\",\n \"value\": [\n \"usr_8545a84e-a45f-41bf-bdf1-33b42a55812c\",\n \"usr_21661ac1-a2a8-4465-a6c0-64474ba8181d\"\n ]\n },\n \"numApprovers\": 2\n },\n \"upstreamPolicyId\": \"root\"\n}", ParameterType.RequestBody); IRestResponse response = client.Execute(request); ``` **`AlwaysTrigger`** ```swift AlwaysTrigger import Foundation let headers = [ "Authorization": "Bearer ", "Content-Type": "application/json" ] let parameters = [ "trigger": [], "rule": [ "type": "approver", "identifierList": [ "type": "userList", "value": ["usr_8545a84e-a45f-41bf-bdf1-33b42a55812c", "usr_21661ac1-a2a8-4465-a6c0-64474ba8181d"] ], "numApprovers": 2 ], "upstreamPolicyId": "root" ] as [String : Any] let postData = JSONSerialization.data(withJSONObject: parameters, options: []) let request = NSMutableURLRequest(url: NSURL(string: "https://api.mercoa.com/entity/ent_8545a84e-a45f-41bf-bdf1-33b42a55812c/approval-policy")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "POST" request.allHTTPHeaderFields = headers request.httpBody = postData as Data let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error as Any) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) } }) dataTask.resume() ```