I am trying to put my instance in Maintenance mode via REST API, as we are publishing Customization Projects VIA REST APIs, but cannot find anything on how to put instance in Lockout or Maintenance Mode ..
- Community
- Discussion Forums
- Develop Integrations with Web Services | APIs
- REST API for: To put instance in Maintenance Mode
REST API for: To put instance in Maintenance Mode
- February 5, 2025
- 3 replies
- 84 views
- Freshman I
- 1 reply
- Semi-Pro II
- February 5, 2025
Hi
if you share us what you have tried, it we will be helpful to suggest.
Also below is the example handling the action Addinvoice button with some parameters. please try this it may helps you.
{
- Freshman I
- February 5, 2025
I wrote below python code to login, import customization project, and publish, via REST APIs, what i want to do before ‘importing’ customization projects , i want to put my site in maintenance mode using similar methods i used in given code, so is there any REST API for that ??
import argparse
import requests
import json
import base64
import logging
import time
from typing import List, Dict
from pathlib import Path
import sys
logging.basicConfig(
format="%(asctime)s [%(levelname)s] %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
level=logging.INFO,
)
logger = logging.getLogger("AcumaticaDeployment")
class DeploymentError(Exception):
pass
def parse_arguments():
parser = argparse.ArgumentParser(description="Deploy packages to Acumatica")
parser.add_argument("--instance-url", required=True, help="Acumatica instance URL")
parser.add_argument("--username", required=True, help="Username for authentication")
parser.add_argument("--password", required=True, help="Password for authentication")
parser.add_argument("--package-date", required=True, help="Package date directory")
return parser.parse_args()
class AcumaticaDeploymentClient:
def __init__(self, instance_url: str, username: str, password: str):
self.base_url = f"{instance_url}/entity/"
self.customization_url = f"{instance_url}/CustomizationApi"
self.session = requests.Session()
self.session.headers.update(
{"Accept": "application/json", "Content-Type": "application/json"}
)
self.username = username
self.password = password
#! Login
def login(self) -> None:
try:
logger.info("=" * 50)
logger.info("Authenticating with Acumatica...")
response = self.session.post(
f"{self.base_url}auth/login",
json={"name": self.username, "password": self.password},
)
response.raise_for_status()
logger.info("Authentication successful")
logger.info("=" * 50)
except requests.exceptions.RequestException as e:
logger.error(f"Authentication failed: {str(e)}")
raise DeploymentError(f"Authentication failed: {str(e)}")
#! Logout
def logout(self) -> None:
try:
logger.info("=" * 50)
logger.info("Logging out...")
response = self.session.post(f"{self.base_url}auth/logout")
response.raise_for_status()
logger.info("Logout successful")
logger.info("=" * 50)
except requests.exceptions.RequestException as e:
logger.warning(f"Logout encountered an issue: {str(e)}")
finally:
self.session.close()
def upload_file(self, file_path: str, project_data: Dict) -> Dict:
try:
logger.info("=" * 50)
logger.info(f"Uploading package: {project_data['projectName']}")
with open(file_path, "rb") as file:
encoded_content = base64.b64encode(file.read()).decode("utf-8")
project_data["projectContentBase64"] = encoded_content
url = f"{self.customization_url}/Import"
response = self.session.post(url=url, json=project_data)
response.raise_for_status()
logger.info(f"Upload successful for package: {project_data['projectName']}")
logger.info("=" * 50)
return {"success": True, "project_name": project_data["projectName"]}
except Exception as e:
logger.error(f"Error uploading {file_path}: {e}")
return {
"success": False,
"project_name": project_data["projectName"],
"error": str(e),
}
def publish_customizations(self, project_names: List[str]) -> Dict:
publish_data = {
"isMergeWithExistingPackages": False,
"isOnlyValidation": False,
"isOnlyDbUpdates": False,
"isReplayPreviouslyExecutedScripts": False,
"projectNames": project_names,
"tenantMode": "Current",
}
try:
logger.info("=" * 50)
logger.info("Starting publication process...")
url = f"{self.customization_url}/publishBegin"
response = self.session.post(url=url, data=json.dumps(publish_data))
response.raise_for_status()
logger.info("Publishing started successfully")
logger.info("=" * 50)
return {"success": True}
except Exception as e:
logger.error(f"Failed to start publishing: {str(e)}")
return {"success": False, "error": str(e)}
def check_publish_status(self) -> Dict:
try:
url = f"{self.customization_url}/publishEnd"
response = self.session.post(url=url, json={})
response.raise_for_status()
status_data = response.json()
return {
"success": True,
"is_complete": status_data.get("isCompleted", False),
"is_failed": status_data.get("isFailed", False),
"logs": status_data.get("log", []),
}
except Exception as e:
logger.error(f"Error checking status: {str(e)}")
return {
"success": False,
"is_complete": False,
"is_failed": True,
"error": str(e),
}
def get_files_config(base_directory: Path) -> List[Dict]:
if not base_directory.exists():
raise FileNotFoundError(f"Directory not found: {base_directory}")
project_configs = [
{
"file_path": "RW.Custoimization1.zip",
"project_data": {
"projectLevel": 1,
"projectName": "RW.Base.CustomizationProj",
"projectDescription": "This Package contains all screens but the GST related screens & dll",
},
},
{
"file_path": "RW.Screens.Extension.Files.CustomizationProj.zip",
"project_data": {
"projectLevel": 2,
"projectName": "RW.Screens.Extension.Files.CustomizationProj",
"projectDescription": "Contains customized screens of Acumatica",
},
},
{
"file_path": "RW.SiteMap.CustomizationProj.zip",
"project_data": {
"projectLevel": 3,
"projectName": "RW.SiteMap.CustomizationProj",
"projectDescription": "Readywire Product Navigation",
},
},
{
"file_path": "RW.Branding.CustomizationProj.zip",
"project_data": {
"projectLevel": 4,
"projectName": "RW.Branding.CustomizationProj",
"projectDescription": "Readywire Branding Info",
},
},
{
"file_path": "RW.Endpoints.CustomizationProj.zip",
"project_data": {
"projectLevel": 5,
"projectName": "RW.Endpoints.CustomizationProj",
"projectDescription": "APIs package",
},
},
{
"file_path": "RW.Security.CustomizationProj.zip",
"project_data": {
"projectLevel": 6,
"projectName": "RW.Security.CustomizationProj",
"projectDescription": "Roles & their access on screens",
},
},
{
"file_path": "RW.BusinessEvents.CustomizationProj.zip",
"project_data": {
"projectLevel": 7,
"projectName": "RW.BusinessEvents.CustomizationProj",
"projectDescription": "Business Events and corresponding Notification Templates",
},
},
{
"file_path": "RW.FinancialReports.CustomizationProj.zip",
"project_data": {
"projectLevel": 8,
"projectName": "RW.FinancialReports.CustomizationProj",
"projectDescription": "Readywire financial reports",
},
},
]
configs = []
for config in project_configs:
file_path = base_directory / config["file_path"]
if not file_path.exists():
logger.warning(f"Customization project file not found: {file_path}")
continue
config["file_path"] = str(file_path)
config["project_data"]["isReplaceIfExists"] = True
configs.append(config)
if not configs:
raise FileNotFoundError(f"No valid package files found in {base_directory}")
return configs
def deploy_packages(instance_url: str, username: str, password: str, package_date: str):
base_directory = Path(rf"C:\Backups\pkg-backups\{package_date}")
client = AcumaticaDeploymentClient(instance_url, username, password)
files_config = get_files_config(base_directory)
project_names = [config["project_data"]["projectName"] for config in files_config]
try:
client.login()
# Wait before upload
logger.info("=" * 50)
logger.info("Waiting 3 seconds before starting upload...")
time.sleep(3)
#! Upload files
logger.info("=" * 50)
logger.info("Starting package uploads...")
upload_results = []
for config in files_config:
result = client.upload_file(config["file_path"], config["project_data"])
upload_results.append(result)
if not result["success"]:
raise DeploymentError(f"Upload failed for {result['project_name']}")
logger.info("=" * 50)
# Wait before publishing
logger.info("=" * 50)
logger.info("Waiting 5 seconds before publishing...")
time.sleep(5)
#! Publish Customization Project
logger.info("=" * 50)
logger.info("Starting publication process...")
publish_result = client.publish_customizations(project_names)
if not publish_result["success"]:
raise DeploymentError("Failed to start publishing")
logger.info("=" * 50)
#! Monitor publish status
logger.info("=" * 50)
logger.info("Monitoring publication status...")
seen_logs = set()
while True:
status = client.check_publish_status()
if not status["success"]:
raise DeploymentError(
f"Error checking publish status: {status.get('error')}"
)
for log_entry in status.get("logs", []):
log_type = log_entry.get("logType", "").upper()
message = log_entry.get("message", "")
log_identifier = f"{log_type}:{message}"
if log_identifier not in seen_logs:
logger.info(f"[{log_type}] {message}")
seen_logs.add(log_identifier)
if status["is_complete"]:
if status["is_failed"]:
raise DeploymentError("Publishing completed with errors")
logger.info("Publishing completed successfully!")
logger.info("=" * 50)
break
time.sleep(5) # Check status every 5 seconds
logger.info("=" * 50)
logger.info("Deployment completed successfully!")
logger.info("=" * 50)
return True
except Exception as e:
logger.error(f"Deployment failed: {str(e)}")
return False
finally:
if client.session.cookies:
client.logout()
def main():
try:
args = parse_arguments()
success = deploy_packages(
instance_url=args.instance_url,
username=args.username,
password=args.password,
package_date=args.package_date,
)
if not success:
sys.exit(1)
except Exception as e:
logger.error(f"Critical error: {str(e)}")
sys.exit(1)
if __name__ == "__main__":
main()

- Jr Varsity I
- April 4, 2025
Hello
Acumatica doesn't provide default REST API endpoints for placing the system in Maintenance Mode, but you can easily implement this by either creating a new Web Service Endpoint or extending an existing one (such as Default
or Manufacturing
). If you already use one of those endpoints in your integrations, extending it would be a better option to avoid switching between multiple endpoints.
For demonstration purposes, I’ll show the process using a new custom endpoint to keep the screenshots clean and focused.
To create the endpoint and enable lockout actions, follow the steps below:
1. Create or Extend a Web Service Endpoint
Go to the Web Service Endpoints screen in Acumatica.
If you want to extend an existing endpoint (like Default
), select it and click Extend Endpoint, then give your extended endpoint a name and version.
If you're creating a new one:
-
Click the Insert (+) button
-
Provide an Endpoint Name and Version
2. Add the "Apply Updates" screen
-
Click Insert under the endpoint structure
-
Select the Apply Updates screen (
SM203510
) -
This screen allows access to the lockout commands
3. Add the scheduleLockoutCommand
Action
-
Expand the
ApplyUpdates
node -
Select the Actions folder and click Insert
-
Choose
scheduleLockoutCommand
from the list of available mapped actions
4. Configure Action Parameters
-
Select the
scheduleLockoutCommand
action -
Go to the Parameters tab and click Populate
-
Select the object Schedule Lockout
-
Select the fields you will use in parameter:
-
DateTime_Date
-
DateTime_Time
-
LockoutAll
-
Reason
-

5. Add the stopLockoutCommand
Action
-
Repeat the same steps as in step 3
-
This time, choose the
stopLockoutCommand
action -
No parameters are needed for this action, so leave the parameter list blank
Example REST API Usage
Schedule Lockout
HTTP Method: POST
URL:
{YourInstanceURL}/entity/{YourEndpointName}/{YourEndpointVersion}/ApplyUpdates/scheduleLockoutCommand
Body:
{
"entity": {},
"parameters": {
"DateTime_Date": {
"value": "4/4/2025"
},
"DateTime_Time": {
"value": "20:50"
},
"LockoutAll": {
"value": "True"
},
"Reason": {
"value": "Maintainance"
}
}
}
Stop Lockout
HTTP Method: POST
URL:
{YourInstanceURL}/entity/{YourEndpointName}/{YourEndpointVersion}/ApplyUpdates/stopLockoutCommand
Body:
{
"entity": {},
"parameters": {}
}
I’m attaching a customization package that includes both:
-
A custom endpoint
-
An extension of the
Default
endpoint from version 23.200.001
You can use whichever fits your setup.
If your Acumatica version is older and there is no Default endpoint with version 23.200.001, simply delete the extended endpoint from the package before publishing (or you can just change the version by editing project.xml file :)).
If you have any questions or run into issues while setting it up, feel free to ask.
1 Attachments
Reply
Related topics
What you may have missed in the Acumatica Community! May, 2022
Acumatica News & Updatesimport snapshot into test environmenticon
Configuration and InstallationREST API PUT requests suddenly return mostly "Sequence contains more than one matching element"icon
Develop Integrations with Web Services | APIsREST API - Add PO Receipt to Bill - Need Helpicon
Develop Integrations with Web Services | APIsREST API: why does retrieving a Sales Price row (AR202000 screen) take so long using HttpClient?icon
Develop Integrations with Web Services | APIs
Most helpful members this week
- harutyungevorgyan
45 likes
- davidnavasardyan
37 likes
- BenjaminCrisman
22 likes
- meganfriesen37
20 likes
- darylbowman
20 likes
Enter your E-mail address. We'll send you an e-mail with instructions to reset your password.
Scanning file for viruses.
Sorry, we're still checking this file's contents to make sure it's safe to download. Please try again in a few minutes.
OKThis file cannot be downloaded
Sorry, our virus scanner detected that this file isn't safe to download.
OKCookie policy
We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.
Cookie settings
We use 3 different kinds of cookies. You can choose which cookies you want to accept. We need basic cookies to make this site work, therefore these are the minimum you can select. Learn more about our cookies.