Create an approval policy

Operation ID: createApprovalPolicy

Group: Base › Approval Policies

Open in the interactive reference

POST /base/approval-policies

Retry-safe: A write that accepts Idempotency-Key: repeating a request with the same key replays the stored answer instead of executing twice.

Creates an approval policy with its rule lines, approvers, exclusion lines, and notification settings. The response contains only the new policy's id. Read the record back with GET base/approval-policies/:id for its stored state, including the assigned policyHeaderNumber. Scope the policy to exactly one thing: name an entityId or set isAllEntities. Naming neither fails with MISSING_ENTITY_SCOPE. Rule lines are evaluated independently. A document picks up the approvers of every line it matches, so two plain lines mean either condition brings in its own approvers, not that both must hold. To require several conditions together, send one line with criteria COMPOSITE whose single value is a JSON AND or OR expression. Every rule line needs at least one approver, or the create fails with LINE_WITHOUT_APPROVERS. An active policy whose business object and entity coverage overlap an existing active policy fails with CONFLICTING_ACTIVE_POLICY. Create it with status 'inActive', or deactivate the other first. Send every value as a string, for example ["10000"], not [10000]. Only a line with valueType 'noValue' may omit the value.

Parameters

Name In Type Required Description
Api-Version header string · v1 yes The API version this request targets, named by its public identifier. Required on every request; omitting it, or naming a version this company does not have, is answered with 400. This document describes version v1.
Idempotency-Key header string no An opaque caller-chosen string (1-255 characters) that makes this request safe to retry. Repeating the same key with an identical request body replays the original response instead of re-executing - but only once that original request succeeded; a failed attempt re-executes on retry. Repeating the key with a different body is answered with 422. A key still in flight is answered with 409 - as is a key whose original request was interrupted before it finished, for a few minutes afterwards, until that attempt is presumed dead. A completed response stays replayable for 24 hours. The key is scoped to the caller, not to the action: reusing it for a different action is answered with 409 or 422 rather than treated independently. On read actions this header is ignored. On write actions that cannot offer the guarantee it is answered with 400 IDEMPOTENCY_NOT_SUPPORTED rather than silently ignored.

Request body

Required, application/json: createApprovalPolicyInput.

Field Type Required Description
entityId string no The legal entity the policy applies to. Required unless isAllEntities is true. Leave it out when using isAllEntities. See id on GET base/entities.
isAllEntities boolean no Whether the policy applies to every legal entity instead of a single one. When true, leave entityId out. Example: true.
businessObject string yes The code of the business object the policy governs. It must be a registered approval business object, for example 'VendorBill', 'ExpenseReport', 'PurchaseOrder', 'PurchaseRequest' or 'JournalEntry'. An unregistered code fails with UNKNOWN_BUSINESS_OBJECT, which lists the registered codes. It cannot be changed after creation. Example: "VendorBill".
status any no The lifecycle status of the policy. Defaults to 'active', which makes it eligible for matching immediately. Create it 'inActive' to stage a policy that would otherwise collide with a live one. One of: "active", "inActive". Example: "active".
startDate string no The first date the policy is eligible for matching. Use format YYYY-MM-DD. Omit for no lower bound.
endDate string no The last date the policy is eligible for matching. Use format YYYY-MM-DD. Omit for no upper bound.
submitterCannotApprove boolean no Whether the document submitter is stopped from approving their own document. When true, their approval does not count toward fulfillment and they are not notified as an approver. Defaults to false.
useSubstitute boolean no Whether an approver who is absent today (approved absence, or a weekend/public holiday running into one) is routed to the substitute on their employee record. The original approver can still approve. Defaults to false.
approverCommentEnabled boolean no Whether approvers are prompted for an optional comment at approve time. The comment is stored on the approval trail. Defaults to false. Example: true.
notification object no The notification channels used when this policy's approvers and submitters are told about a document. Omit to leave the tenant's defaults in place. Example: {"emailNotification":true}.
notification.emailNotification boolean no Whether to email approvers.
notification.nativeNotification boolean no Whether to raise an in-product notification for approvers.
notification.slackNotification boolean no Whether to notify approvers on Slack.
lines array<object> yes The policy's rule lines. It must not be empty. Rule lines are evaluated independently: a document picks up the approvers of every line it matches. To require several conditions together, use one COMPOSITE line rather than several plain lines. Example: [{"criteria":"Total Amount","operator":"Greater Than","value":["10000"],"valueType":"number","step":1,"requireAction":"All","approvers":[{"approverId":42,"approverType":"employee"}]}].
lines[].criteria string yes The document field the rule tests. Use the criteria names the document type publishes, for example 'Vendor', 'Total Amount', 'Department', 'Line Amounts' or 'Upon Creation'. Pass the literal COMPOSITE to combine several conditions in one line.
lines[].operator string yes The comparison to apply to the criteria, for example 'Equal', 'Not Equal', 'Greater Than', 'Less Than', 'In', 'Intersect' or the Any and All variants for array fields. Use '-' for a criteria that takes no value.
lines[].value array<string> no The values to compare against, each as a string, for example ["10000"], not [10000]. Omit only when valueType is 'noValue'. A 'number' valueType takes exactly one numeric element. A 'composite' valueType takes exactly one element holding the JSON expression, for example {"operator":"AND","children":[{"criteriaName":"Vendor","operator":"Equal","value":["Acme"],"valueType":"multivalue"},{"criteriaName":"Total Amount","operator":"Less Than","value":["10000"],"valueType":"number"}]}.
lines[].valueType any yes How to interpret value. 'number' is a single numeric comparison, 'multivalue' one or more discrete values, 'value' a single discrete value, 'noValue' a criteria that takes none such as 'Upon Creation', 'arrayField' the Any, All and Intersect operators over a line-level array, and 'composite' a COMPOSITE expression. One of: "number", "multivalue", "value", "noValue", "arrayField", "composite".
lines[].step number yes The approval order, starting at 1. Lines that share a step are approved together, and a higher step is reached only once the lower steps are satisfied.
lines[].requireAction any no Whether all of the line's approvers must approve, or any one of them is enough. Defaults to 'All'. One of: "All", "Any".
lines[].approvers array<object> yes The approvers for this line. It must not be empty, because a line with no approver can never be satisfied.
lines[].approvers[].approverId number yes The approver. For approverType 'employee' or 'supremeApprover' it is the employee, and for 'manager' it is the manager-hierarchy record. It is an integer, not a UUID. There is no endpoint for it.
lines[].approvers[].approverType any yes The kind of approver. 'employee' names a specific person, 'manager' resolves the submitter's manager through a hierarchy at approval time, and 'supremeApprover' is a person who may approve at any step. One of: "employee", "manager", "supremeApprover".
exclusionLines array<object> no The exclusion lines. A document matching any of them is exempted from the policy entirely, whatever the rule lines say. Omit for no exclusions.
exclusionLines[].criteria string yes
exclusionLines[].operator string yes
exclusionLines[].value array<string> no The values to compare against, each as a string. Omit only when valueType is 'noValue'.
exclusionLines[].valueType any yes One of: "number", "multivalue", "value", "noValue", "arrayField", "composite".
{
  "entityId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "isAllEntities": true,
  "businessObject": "VendorBill",
  "status": "active",
  "startDate": "<startDate>",
  "endDate": "<endDate>",
  "submitterCannotApprove": true,
  "useSubstitute": true,
  "approverCommentEnabled": true,
  "notification": {
    "emailNotification": true
  },
  "lines": [
    {
      "criteria": "Total Amount",
      "operator": "Greater Than",
      "value": [
        "10000"
      ],
      "valueType": "number",
      "step": 1,
      "requireAction": "All",
      "approvers": [
        {
          "approverId": 42,
          "approverType": "employee"
        }
      ]
    }
  ],
  "exclusionLines": [
    {
      "criteria": "<criteria>",
      "operator": "<operator>",
      "value": [
        "<value>"
      ],
      "valueType": "number"
    }
  ]
}

Response

200 Success

Under data (createApprovalPolicyOutput):

Field Type Required Description
id string yes The unique identifier for the created approval policy. Every other approval-policy endpoint is keyed by it. Example: "9c1f4b62-7d38-4a05-b1e7-2f6a8c093d54".
{
  "data": {
    "id": "9c1f4b62-7d38-4a05-b1e7-2f6a8c093d54"
  },
  "diagnostics": [
    {
      "code": "<code>",
      "message": "<message>",
      "severity": "error",
      "path": [
        "<path>"
      ],
      "details": "<details>"
    }
  ]
}

Response headers

Errors

Code Status
MISSING_ENTITY_SCOPE 400
ENTITY_NOT_FOUND 400
UNKNOWN_BUSINESS_OBJECT 400
NO_LINES 400
LINE_WITHOUT_APPROVERS 400
MISSING_LINE_VALUE 400
INVALID_NUMBER_VALUE 400
INVALID_COMPOSITE_EXPRESSION 400
CONFLICTING_ACTIVE_POLICY 400
IDEMPOTENCY_KEY_CONFLICT 409
IDEMPOTENCY_PAYLOAD_MISMATCH 422

Statuses