Approvals

Beta

Manager sign-off above org-configured limits (discount %, credit, PO total, expense amount). A document that needs approval can't be finalised: writes return 409 approval_required with the reasons, or hold it when the body has submitForApproval: true.

GET/api/v1/approvals

List approval requests

Scope: approvals.read

Parameters

NameInTypeRequiredDescription
statusquerystringOptionalPENDING, APPROVED, REJECTED or CANCELLED.
docTypequerystringOptionalQUOTE, SALES_ORDER, INVOICE, PURCHASE_ORDER or EXPENSE.
pagequerynumberOptional1-based page number.
limitquerynumberOptionalPage size, max 200.

Example request

curl "https://invoice.avscorp.in/api/v1/approvals" \
  -H "Authorization: Bearer YOUR_API_KEY"

Example response

JSON
{
  "id": "clx9apr00000000000000001",
  "docType": "INVOICE",
  "docId": "clx2inv001000000000000001",
  "status": "PENDING",
  "reasons": [
    {
      "rule": "DISCOUNT_PERCENT",
      "message": "Discount 18% exceeds the 10% limit",
      "value": "18",
      "limit": "10"
    }
  ],
  "snapshot": {
    "totalBase": "11800",
    "currencyCode": "INR",
    "exchangeRate": "1",
    "maxDiscountPct": "18",
    "customerId": "clx1cus000000000000000001"
  },
  "requestedBy": "clxusr0000000000000000002",
  "decidedBy": null,
  "decidedAt": null,
  "decisionNote": null,
  "cancelReason": null,
  "createdAt": "2026-10-26T10:00:00.000Z"
}

Possible errors: unauthorized, insufficient_scope, forbidden, validation_error

POST/api/v1/approvals

Submit a draft for approval

Scope: approvals.read

Re-evaluates the saved draft (or held expense). Returns { needed: false } when no rule trips any more. Also needs the document's own update scope (expenses.create for expenses).

Request body

FieldTypeRequiredConstraints
docTypestringRequiredone of: QUOTE, SALES_ORDER, INVOICE, PURCHASE_ORDER, EXPENSE
docIdstringRequiredmin length 1; max length 30

Example request

curl -X POST "https://invoice.avscorp.in/api/v1/approvals" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "docType": "INVOICE",
  "docId": "clx2inv001000000000000001"
}'

Example response

JSON
{
  "needed": true,
  "requestId": "clx9apr00000000000000001",
  "reasons": [
    {
      "rule": "DISCOUNT_PERCENT",
      "message": "Discount 18% exceeds the 10% limit",
      "value": "18",
      "limit": "10"
    }
  ]
}

Possible errors: unauthorized, insufficient_scope, forbidden, not_found, conflict, validation_error

POST/api/v1/approvals/{id}/approve

Approve a request

Scope: approvals.approve

Only PENDING requests; nobody approves their own. Approving an expense posts it.

Parameters

NameInTypeRequiredDescription
idpathstringRequiredApproval request ID.

Example request

curl -X POST "https://invoice.avscorp.in/api/v1/approvals/clx9apr00000000000000001/approve" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "note": "OK for this customer"
}'

Example response

JSON
{
  "id": "clx9apr00000000000000001",
  "docType": "INVOICE",
  "docId": "clx2inv001000000000000001",
  "status": "APPROVED",
  "reasons": [
    {
      "rule": "DISCOUNT_PERCENT",
      "message": "Discount 18% exceeds the 10% limit",
      "value": "18",
      "limit": "10"
    }
  ],
  "snapshot": {
    "totalBase": "11800",
    "currencyCode": "INR",
    "exchangeRate": "1",
    "maxDiscountPct": "18",
    "customerId": "clx1cus000000000000000001"
  },
  "requestedBy": "clxusr0000000000000000002",
  "decidedBy": "clxusr0000000000000000001",
  "decidedAt": "2026-10-26T11:00:00.000Z",
  "decisionNote": null,
  "cancelReason": null,
  "createdAt": "2026-10-26T10:00:00.000Z"
}

Possible errors: unauthorized, insufficient_scope, forbidden, not_found, conflict

POST/api/v1/approvals/{id}/reject

Reject a request

Scope: approvals.approve

A note is required. The document stays a draft (an expense stays held).

Parameters

NameInTypeRequiredDescription
idpathstringRequiredApproval request ID.

Example request

curl -X POST "https://invoice.avscorp.in/api/v1/approvals/clx9apr00000000000000001/reject" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "note": "Discount too high for this account"
}'

Example response

JSON
{
  "id": "clx9apr00000000000000001",
  "docType": "INVOICE",
  "docId": "clx2inv001000000000000001",
  "status": "REJECTED",
  "reasons": [
    {
      "rule": "DISCOUNT_PERCENT",
      "message": "Discount 18% exceeds the 10% limit",
      "value": "18",
      "limit": "10"
    }
  ],
  "snapshot": {
    "totalBase": "11800",
    "currencyCode": "INR",
    "exchangeRate": "1",
    "maxDiscountPct": "18",
    "customerId": "clx1cus000000000000000001"
  },
  "requestedBy": "clxusr0000000000000000002",
  "decidedBy": "clxusr0000000000000000001",
  "decidedAt": null,
  "decisionNote": "Discount too high for this account",
  "cancelReason": null,
  "createdAt": "2026-10-26T10:00:00.000Z"
}

Possible errors: unauthorized, insufficient_scope, forbidden, not_found, conflict, validation_error