### Testing Webhooks with Third-Party Services Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-board-webhooks/readme.md This example shows how to use a service like webhook.site to test your webhook setup. Ensure you use an HTTPS URL and unsubscribe after testing. ```bash $ python3 board_subscription.py BOARD_ID --webhook-url https://webhook.site/c2654750-fc30-4412-a6b1-fc81baaef070 ``` -------------------------------- ### Install Requirements Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-list-document-archive/readme.md Install the necessary third-party libraries for the script to function correctly. Refer to the requirements.txt file for a complete list. ```bash pip install -r requirements.txt ``` -------------------------------- ### Run the Node.js Import Script Source: https://github.com/projectplace/api-code-examples/blob/main/examples/node-js-import-cards-with-excel/readme.md Execute the Node.js script from your terminal to initiate the card import process. Ensure all dependencies are installed. ```bash node Import_Cards_From_Xlsx.js ``` -------------------------------- ### OAuth2 Client Credentials Authentication Source: https://context7.com/projectplace/api-code-examples/llms.txt This example demonstrates how to obtain an access token using OAuth2 Client Credentials and then list active workspaces. ```APIDOC ## Obtain Access Token ### Description Authenticates using client ID and secret to obtain an OAuth2 access token. ### Method POST ### Endpoint /oauth2/access_token ### Parameters #### Query Parameters - **grant_type** (string) - Required - Must be 'client_credentials' #### Request Body (None) ### Request Example ``` POST /oauth2/access_token HTTP/1.1 Host: mycompany.projectplace.com Content-Type: application/x-www-form-urlencoded grant_type=client_credentials ``` ### Response #### Success Response (200) - **access_token** (string) - The obtained access token. #### Response Example ```json { "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI..." } ``` ## List Active Workspaces ### Description Retrieves a list of active workspaces, sorted by creation date, with a specified limit. ### Method POST ### Endpoint /2/account/projects ### Parameters #### Query Parameters (None) #### Request Body - **sort_by** (string) - Optional - Specifies the sorting order (e.g., '+creation_date'). - **filter** (object) - Optional - Filters the results. - **archive_status** (array) - Optional - Filters by archive status (e.g., [0] for active). - **limit** (integer) - Optional - The maximum number of workspaces to return. ### Request Example ```json { "sort_by": "+creation_date", "filter": {"archive_status": [0]}, "limit": 5 } ``` ### Response #### Success Response (200) - **name** (string) - The name of the workspace. - **id** (integer) - The ID of the workspace. #### Response Example ```json [ { "name": "Alpha Project", "id": 1001 }, { "name": "Beta Initiative", "id": 1002 } ] ``` ``` -------------------------------- ### Example: Rename Second Column Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-enforce-column-name/readme.md This example renames the second column (index 1) in all boards to 'In Progress'. ```bash $ python3 enforce_column_names.py 1 "In Progress" ``` -------------------------------- ### Bulk Update User Email Addresses Source: https://context7.com/projectplace/api-code-examples/llms.txt This example shows how to bulk update user email addresses by reading a CSV file, validating against account members, and applying changes. ```APIDOC ## Change User Email Address ### Description Adds a secondary email address to a user's account. This is part of a bulk update process. ### Method POST ### Endpoint /1/account/people/{user_id} ### Parameters #### Path Parameters - **user_id** (integer) - Required - The ID of the user whose email address to change. #### Query Parameters (None) #### Request Body - **action** (string) - Required - Must be 'add_secondary_email'. - **params** (array) - Required - Contains the new email address as a string. ### Request Example ```json { "action": "add_secondary_email", "params": ["new@company.com"] } ``` ### Response #### Success Response (200) - **succeeded** (array of strings) - List of user IDs for whom the action succeeded. - **failed** (array of strings) - List of user IDs for whom the action failed. #### Response Example ```json { "succeeded": ["123"], "failed": [] } ``` ``` -------------------------------- ### Example: Rename First Column Conditionally Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-enforce-column-name/readme.md This example renames the first column (index 0) to 'Backlog' only if its current name is 'Planned'. ```bash $ python3 enforce_column_names.py 0 "Backlog" -o "Planned" ``` -------------------------------- ### Get User Owned Artifacts with Python Source: https://context7.com/projectplace/api-code-examples/llms.txt Retrieves all artifacts owned by a specific user. Requires the user_id obtained from a previous query. ```python user_id = inactive[0]['userid'] owned = requests.get( f'{API_ENDPOINT}/1/account/people/{user_id}/owned-artifacts', auth=oauth1 ).json() # {"USER_ID": {"projects_data": {"projects_owner": [...]}, "portfolios_owner": [...], ...}} ``` -------------------------------- ### Card Status Change Webhook Payload Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-board-webhooks/readme.md This is an example of the JSON payload that will be sent to your webhook URL when a card's column is changed on a board. ```json { // The ID of the subscription: "id": "649c37e5fdfaa1bf202a098e", // The artifact type "board": "artifact_type": "board", // The ID of the Board: "artifact_id": 1358069, // The event type that caused the payload to sent to the webhook url "event_type": "card_status_change", // The time at which the event was triggered: "ts": 1687960180.368427, // A representation of the affected card: "contents": { "access": "write", "all_attachments": [], "assignee": null, "assignee_id": null, "board_column_order": 1, "board_id": 1358069, "board_name": "Test Board Hooks", "checklist": null, "column_first_updated": "2023-06-28 13:49:40Z", "column_id": 1, "column_last_updated": "2023-06-28 13:49:40Z", "comment_count": 0, "connected_issues": [], "connected_risks": [], "contributors": [], "created_time": "2023-06-28 13:49:31Z", "creator": { "avatar": "/images/00/16/ed/7317-a98d28e5.jpeg", "id": 259895408, "name": "NAME OF CARD CREATOR", "type": "User" }, "dependencies": { "predecessors": 0, "predecessors_done": 0, "successors": 0, "successors_done": 0 }, "description": "", "direct_url": "https://service.projectplace.com/#direct/card/18776663", "display_order": 125000, "due_date": null, "due_date_offset": null, "estimate": null, "estimated_time": null, "id": 18776663, "is_blocked": false, "is_blocked_reason": null, "is_done": false, "is_template": false, "label_id": null, "local_id": 154, "planlet": { "id": 978642950, "name": "123", "wbs_id": "1" }, "planlet_id": 978642950, "progress": { "id": 1 }, "project": { "id": 663309443, "is_team_member_plus": false, "is_team_member_plus_plan": null, "name": "TITLE OF WORKSPACE", "override_tm_plus_time_reporting": false, "type": "classic" }, "reported_time": null, "start_date": null, "start_date_offset": null, "title": "TITLE OF CARD" } } ``` -------------------------------- ### Create and Delete a Project Source: https://github.com/projectplace/api-code-examples/blob/main/auth/py-oauth1/readme.md Executes the script to create a project with a specified name and then immediately delete it, using OAuth1 authentication. ```bash python oauth1_flow.py create-project "My Project Name" ``` -------------------------------- ### Run Script to Download Workspaces Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-download-archived-workspaces/readme.md Execute the script to loop through all workspaces, trigger export jobs, wait for completion, and download each workspace as a zip file to the current directory. ```bash $ python3 download_workspaces.py ``` -------------------------------- ### Run Script with Custom Download Path Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-download-archived-workspaces/readme.md Specify a custom directory for downloaded workspace zip files using the -p argument. ```bash $ python3 download_workspaces.py -p /Users/MyUser/WorkspaceDownloads ``` -------------------------------- ### Subscribe to Card Column Changes Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-board-webhooks/readme.md Execute this command to set up a webhook subscription for card status changes on a specific board. Provide the BOARD_ID and your webhook URL. ```bash $ python3 board_subscription.py BOARD_ID --webhook-url https://URL_TO_YOUR_WEBHOOK_ENDPOINT.com ``` -------------------------------- ### Consume OData API with Python Source: https://context7.com/projectplace/api-code-examples/llms.txt Fetches data from Projectplace OData endpoints, including listing entity sets and downloading data with gzip compression. Requires client credentials for authentication. ```python import gzip, json, requests, requests.auth from datetime import datetime CLIENT_ID = 'your_robot_client_id' CLIENT_SECRET = 'your_robot_client_secret' ODATA_BASE_URL = 'https://odata3.projectplace.com' ACCESS_TOKEN_URL = 'https://api.projectplace.com/oauth2/access_token' # Get access token (client credentials) token_resp = requests.post( ACCESS_TOKEN_URL, data={'grant_type': 'client_credentials'}, auth=requests.auth.HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET) ) token_resp.raise_for_status() access_token = token_resp.json()['access_token'] headers = {'Authorization': f'Bearer {access_token}'} # List available entity sets in the account (am) endpoint entity_sets = requests.get(f'{ODATA_BASE_URL}/am', headers=headers).json()['value'] for i, es in enumerate(entity_sets): print(f'{i+1}. {es["name"]}') # 1. AccountWorkspaces # 2. AccountUsers # ... # Download an entity set with streaming (gzip output) entity_set = 'AccountWorkspaces' odata_endpoint = 'am' file_name = f'{odata_endpoint}_{entity_set}_{datetime.now().date().isoformat()}.json.gz' with gzip.open(file_name, 'wb') as f: with requests.get(f'{ODATA_BASE_URL}/{odata_endpoint}/{entity_set}', headers=headers, stream=True) as r: r.raise_for_status() for chunk in r.iter_content(chunk_size=102400): f.write(chunk) # Read back and verify with gzip.open(file_name, 'rb') as f: data = json.load(f) print(f'Downloaded {len(data["value"])} entries to {file_name}') # Downloaded 342 entries to am_AccountWorkspaces_2024-05-11.json.gz # CLI usage: # python consume_odata.py # python consume_odata.py --avoid-streaming # writes plain .json instead of .gz ``` -------------------------------- ### Configure Robot Account Credentials Source: https://github.com/projectplace/api-code-examples/blob/main/auth/py-oauth2-client-credentials/readme.md Replace placeholder values with your actual robot account credentials and subdomain. These are required for authentication. ```python CLIENT_ID = 'your_robot_client_id_here' CLIENT_SECRET = 'your_robot_client_secret_here' SUBDOMAIN = 'your_subdomain_here' ``` -------------------------------- ### Authenticate and List Workspaces with OAuth2 Client Credentials Source: https://context7.com/projectplace/api-code-examples/llms.txt Obtains an access token using OAuth2 client credentials and then lists the first 5 active workspaces. Requires `CLIENT_ID`, `CLIENT_SECRET`, and `SUBDOMAIN` to be set. ```python import requests import requests.auth CLIENT_ID = 'your_robot_client_id' CLIENT_SECRET = 'your_robot_client_secret' SUBDOMAIN = 'mycompany' API_ENDPOINT = f'https://{SUBDOMAIN}.projectplace.com' # Obtain an access token response = requests.post( f'{API_ENDPOINT}/oauth2/access_token', data={'grant_type': 'client_credentials'}, auth=requests.auth.HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET) ) response.raise_for_status() access_token = response.json()['access_token'] # "eyJhbGciOiJSUzI1NiIsInR5cCI..." # List first 5 active workspaces workspaces = requests.post( f'{API_ENDPOINT}/2/account/projects', json={ 'sort_by': '+creation_date', 'filter': {'archive_status': [0]}, 'limit': 5 }, headers={'Authorization': f'Bearer {access_token}'} ).json() for ws in workspaces: print(f' - {ws["name"]} (ID: {ws["id"]})') # - Alpha Project (ID: 1001) # - Beta Initiative (ID: 1002) ``` -------------------------------- ### Run the OAuth2 Client Credentials Script Source: https://github.com/projectplace/api-code-examples/blob/main/auth/py-oauth2-client-credentials/readme.md Executes the Python script to obtain an access token and retrieve workspace information. ```bash python oauth2_client_credentials.py ``` -------------------------------- ### Configure Authorization Attributes Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-list-document-archive/readme.md Replace placeholder values with your application key, secret, and OAuth1 token details. Ensure these are kept confidential. ```python APPLICATION_KEY = 'REDACTED' APPLICATION_SECRET = 'REDACTED' ACCESS_TOKEN_KEY = 'REDACTED' ACCESS_TOKEN_SECRET = 'REDACTED' API_ENDPOINT = 'https://api.projectplace.com' ``` -------------------------------- ### Run Script to Interactively Select Document Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-download-document/readme.md Run the script without the -d DOCUMENT_ID argument to interactively select a workspace, navigate document archives, and choose a document for download. ```bash $ python3 download_document.py ``` -------------------------------- ### Select Entity Set for Account Data Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-consume-odata/readme.md After selecting 'Account data', the script lists available entity sets within that category and prompts the user to choose one for download. ```text The following entity sets are available for Account data: 1. AccountPeople 2. AccountWorkspaces 3. AccountWorkspaceMembers 4. Requests 5. WorkspaceCustomField 6. RequestCustomFormFields Which entity set would you like to download? ``` -------------------------------- ### Configure Robot Account Credentials Source: https://github.com/projectplace/api-code-examples/blob/main/auth/py-oauth1/readme.md Set your OAuth1 robot account credentials and subdomain. Replace placeholder values with your actual credentials. ```python APPLICATION_KEY = 'your_application_key_here' APPLICATION_SECRET = 'your_application_secret_here' ACCESS_TOKEN_KEY = 'your_access_token_key_here' ACCESS_TOKEN_SECRET = 'your_access_token_secret_here' SUBDOMAIN = 'your_subdomain_here' ``` -------------------------------- ### Download OData Account Workspaces Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-consume-odata/readme.md Initiates the download of data from the 'am/AccountWorkspaces' entity set. Data is streamed and displayed in MB during download. ```text Downloading am/AccountWorkspaces please wait... 1.21 MB ``` -------------------------------- ### Download Archived Workspaces with Python Source: https://context7.com/projectplace/api-code-examples/llms.txt Streams archived workspaces to disk as ZIP files. Optionally purges workspaces after download. Uses OAuth1 for authentication and requires application keys and token credentials. ```python # examples/py-download-archived-workspaces/download_workspaces.py import time, requests, requests_oauthlib API_ENDPOINT = 'https://api.projectplace.com' oauth1 = requests_oauthlib.OAuth1('APP_KEY', 'APP_SECRET', 'TOKEN_KEY', 'TOKEN_SECRET') # Fetch all archived workspaces (paginated) def fetch_archived(limit=100, row_number=0): body = {'sort_by': '+creation_date', 'filter': {'archive_status': [1]}, 'limit': limit} if row_number: body['row_number'] = row_number return requests.post(f'{API_ENDPOINT}/2/account/projects', json=body, auth=oauth1).json() archived = fetch_archived() print(f'Found {len(archived)} archived workspaces') # Trigger export job for a workspace def trigger_export(project_id): r = requests.post( f'{API_ENDPOINT}/1/projects/{project_id}/exports', json={ 'include_documents': True, 'include_all_document_versions': True, 'include_plan': True, 'include_boards': True, 'include_conversations': True, }, auth=oauth1 ) r.raise_for_status() return r.json() # export_id (int) # Poll until the export is complete def await_export(project_id, export_id): while True: time.sleep(5) result = requests.get( f'{API_ENDPOINT}/1/projects/{project_id}/exports/{export_id}', auth=oauth1 ).json() if result['done']: return result # {"done": true, "download_uri": "...", "download_name": "MyProject-2024-05-11.zip"} # Stream the ZIP to disk def download_export(project_id, download_name, download_uri): file_path = f'{project_id}-{download_name}' with requests.get(download_uri, auth=oauth1, stream=True) as r: r.raise_for_status() with open(file_path, 'wb') as fp: for chunk in r.iter_content(chunk_size=2097152): # 2 MB chunks fp.write(chunk) print(f'Saved: {file_path}') # CLI usage: # python download_workspaces.py # python download_workspaces.py --purge-after-download # python download_workspaces.py --path /data/exports ``` -------------------------------- ### View Account Information Source: https://github.com/projectplace/api-code-examples/blob/main/auth/py-oauth1/readme.md Executes the script to retrieve account information using OAuth1 authentication. ```bash python oauth1_flow.py account-info ``` -------------------------------- ### Import Cards from Excel using Node.js Source: https://context7.com/projectplace/api-code-examples/llms.txt Reads an Excel file and creates board cards in ProjectPlace. Maps spreadsheet columns to card fields, handles blocking status, and reports import results. Requires 'node-xlsx', 'request', and 'prompt-sync' npm packages. ```javascript // examples/node-js-import-cards-with-excel/Import_Cards_From_Xlsx.js // Install: npm install (see package.json for node-xlsx, request, prompt-sync) // Run: node Import_Cards_From_Xlsx.js const xlsx = require('node-xlsx'); const request = require('request'); const ACCESS_TOKEN = 'your_oauth2_bearer_token'; const WORKSPACE_ID = '1001'; const FILE_PATH = '/path/to/cards.xlsx'; // Expected Excel headers (case-insensitive, any order): // board id | title | description | due date | assignee | label | points | // estimated time | blocked reason | column | checklist | activity const sheets = xlsx.parse(FILE_PATH); const sheet = sheets[0]; // use first sheet // Build header-to-column-index mapping const headers = {}; sheet.data[0].forEach((h, i) => { headers[h.toLowerCase()] = i; }); const rows = sheet.data.slice(1).filter(r => r.length > 0); async function createCard(row) { const blockedReason = row[headers['blocked reason']]; const card = { board_id: row[headers['board id']], title: row[headers['title']], description: row[headers['description']], due_date: row[headers['due date']], assignee_id: row[headers['assignee']], label_id: row[headers['label']], estimate: row[headers['points']], estimated_time: row[headers['estimated time']], column_id: row[headers['column']], planlet_id: row[headers['activity']], is_blocked: blockedReason ? 1 : 0, block_reason: blockedReason, checklist: row[headers['checklist']] ? row[headers['checklist']].split('##') : [] }; return new Promise((resolve) => { request.post( `https://api.projectplace.com/1/projects/${WORKSPACE_ID}/cards/create-new`, { auth: { bearer: ACCESS_TOKEN }, json: card }, (err, res, body) => { if (res.statusCode !== 200) { console.error(`Failed: ${card.title}`, body); } else { console.log(`Created: ${card.title} (status ${res.statusCode})`); } resolve(body); } ); }); } (async () => { for (const row of rows) { await createCard(row); } console.log('Import complete.'); })(); ``` -------------------------------- ### Configure OAuth2 Credentials Source: https://github.com/projectplace/api-code-examples/blob/main/auth/py-oauth2-authorization-code/readme.md Set your application's client ID, client secret, and subdomain. These are required for the OAuth2 flow. ```python CLIENT_ID = 'your_client_id_here' CLIENT_SECRET = 'your_client_secret_here' SUBDOMAIN = 'your_subdomain_here' ``` -------------------------------- ### Run Script to Download Document by ID Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-download-document/readme.md Execute the script with the -d DOCUMENT_ID argument to directly download a specific document to the working directory. ```bash $ python3 download_document.py -d DOCUMENT_ID ``` -------------------------------- ### Run Authorization Code Flow Script Source: https://github.com/projectplace/api-code-examples/blob/main/auth/py-oauth2-authorization-code/readme.md Executes the Python script to initiate the OAuth2 Authorization Code flow. This will open a browser for authorization and handle token exchange. ```bash python oauth2_authorization_code.py ``` -------------------------------- ### Run Script to Download and Delete Workspaces Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-download-archived-workspaces/readme.md Use the -d argument to delete archived workspaces from ProjectPlace after they have been successfully downloaded. Only downloaded workspaces are eligible for deletion. ```bash $ python3 download_workspaces -p /Users/MyUser/WorkspaceDownloads -d ``` -------------------------------- ### Download Document from Workspace with Python Source: https://context7.com/projectplace/api-code-examples/llms.txt Lists documents and folders within a workspace or specific folder, and streams a chosen document to the local filesystem. Supports direct download by document ID. Uses OAuth1 for authentication. ```python # examples/py-download-document/download_document.py import urllib.parse, requests, requests_oauthlib API_ENDPOINT = 'https://api.projectplace.com' oauth1 = requests_oauthlib.OAuth1('APP_KEY', 'APP_SECRET', 'TOKEN_KEY', 'TOKEN_SECRET') # List documents in a workspace (or folder) def get_container_contents(container_id): return requests.get( f'{API_ENDPOINT}/2/documents/{container_id}', auth=oauth1 ).json()['contents'] # [{"id": 201, "type": "Folder", "file_name": "Reports"}, {"id": 202, "type": "Document", ...}] ``` -------------------------------- ### Manage Board Webhooks with OAuth1 Source: https://context7.com/projectplace/api-code-examples/llms.txt Demonstrates subscribing to, listing, updating, and deleting `card_status_change` webhooks for a specific board. Requires `APP_KEY`, `APP_SECRET`, `TOKEN_KEY`, `TOKEN_SECRET`, `BOARD_ID`, and `WEBHOOK_URL` to be configured. The `project_id` for the webhook must be retrieved separately. ```python # examples/py-board-webhooks/board_subscription.py import requests import requests_oauthlib API_ENDPOINT = 'https://api.projectplace.com' oauth1 = requests_oauthlib.OAuth1('APP_KEY', 'APP_SECRET', 'TOKEN_KEY', 'TOKEN_SECRET') BOARD_ID = 42 WEBHOOK_URL = 'https://my-server.example.com/webhook' # Subscribe to card status change events on a board new_webhook = requests.post( f'{API_ENDPOINT}/1/webhooks', json={ 'artifact_type': 'board', 'artifact_id': BOARD_ID, 'event_type': ['card_status_change'], 'project_id': 99, # retrieved from GET /1/boards/{board_id} 'webhook': WEBHOOK_URL }, auth=oauth1 ).json() print(new_webhook) # {"id": 55, "artifact_type": "board", "artifact_id": 42, "webhook": "https://...", ...} # List all webhooks for a board webhooks = requests.get(f'{API_ENDPOINT}/1/webhooks/list', auth=oauth1).json() board_webhooks = [w for w in webhooks if w['artifact_id'] == BOARD_ID] print(board_webhooks) # Update an existing webhook URL requests.put( f'{API_ENDPOINT}/1/webhooks/55/update', json={'event_type': ['card_status_change'], 'webhook': 'https://new-url.example.com/hook'}, auth=oauth1 ) # Delete a webhook requests.delete(f'{API_ENDPOINT}/1/webhooks/55', auth=oauth1) # CLI usage: # python board_subscription.py 42 --webhook_url https://my-server.example.com/webhook # python board_subscription.py 42 --unsubscribe ``` -------------------------------- ### Run Script to Upload Document to Workspace Root Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-upload-document/readme.md Execute the Python script to upload a file to the root of a selected workspace. The script will prompt you to choose a workspace after execution. ```bash $ python3 upload-document.py PATH_TO_FILE ``` -------------------------------- ### OAuth1 Robot Account Authentication with Python Source: https://context7.com/projectplace/api-code-examples/llms.txt Demonstrates OAuth1 authentication for making API calls without user interaction. Requires pre-configured credentials and a subdomain. The OAuth1 session is passed to requests. ```Python # auth/py-oauth1/oauth1_flow.py import requests import requests_oauthlib APPLICATION_KEY = 'your_application_key' APPLICATION_SECRET = 'your_application_secret' ACCESS_TOKEN_KEY = 'your_access_token_key' ACCESS_TOKEN_SECRET = 'your_access_token_secret' SUBDOMAIN = 'mycompany' API_ENDPOINT = f'https://{SUBDOMAIN}.projectplace.com' oauth = requests_oauthlib.OAuth1( client_key=APPLICATION_KEY, client_secret=APPLICATION_SECRET, resource_owner_key=ACCESS_TOKEN_KEY, resource_owner_secret=ACCESS_TOKEN_SECRET ) # GET account info response = requests.get(f'{API_ENDPOINT}/1/account', auth=oauth) print(response.json()) # {"id": 1234, "name": "My Company", "managers": [{"id": 5678, "name": "Alice"}], ...} # POST create a project owner_id = response.json()['managers'][0]['id'] project = requests.post( f'{API_ENDPOINT}/1/account/projects', data={'name': 'My New Project', 'owner_id': owner_id}, auth=oauth ).json() print(project) # {"id": 9999, "name": "My New Project", ...} # DELETE a project del_response = requests.delete(f'{API_ENDPOINT}/1/projects/{project["id"]}', auth=oauth) print(del_response.status_code) # 200 # Run from CLI: # python oauth1_flow.py account-info # python oauth1_flow.py create-project "My Project Name" ``` -------------------------------- ### CSV File Format for Email Changes Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-bulk-update-emails/readme.md Prepare a comma-separated file mapping existing email addresses to new ones. The left column is the current email, and the right column is the new email to be added as primary. ```csv jdoe@organisation.org,john.doe@organisation.org bhall@organisation.org,belinda.hall@organisation.org boboue@organisation.org,brent.oboue@newdomain.org ``` -------------------------------- ### Select OData Endpoint Category Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-consume-odata/readme.md The script prompts the user to choose between Workspace, Account, or Portfolio data. This selection determines which OData endpoint will be queried. ```text The following ODATA collections are available 1. Workspace data 2. Account data 3. Portfolio data Which would you like to investigate? (1, 2, 3): ``` -------------------------------- ### Download Document by Metadata Source: https://context7.com/projectplace/api-code-examples/llms.txt Downloads a document using its metadata object. Requires OAuth1 authentication and saves the file locally. ```python import urllib.parse import requests API_ENDPOINT = 'https://api.projectplace.com' def download_document(document): filename = urllib.parse.unquote(document['os_file_name']) with requests.get(f'{API_ENDPOINT}/1/documents/{document["id"]}', auth=oauth1, stream=True) as r: r.raise_for_status() with open(filename, 'wb') as fp: for chunk in r.iter_content(chunk_size=8192): fp.write(chunk) print(f'Downloaded: {filename}') # Direct download by document ID doc_id = 202 document_meta = requests.get(f'{API_ENDPOINT}/2/documents/{doc_id}', auth=oauth1).json() download_document(document_meta) # List accessible workspaces workspaces = requests.get(f'{API_ENDPOINT}/1/user/me/projects', auth=oauth1).json() for ws in workspaces: print(f'{ws["name"]} — ID: {ws["id"]}') # CLI usage (interactive): # python download_document.py # CLI usage (direct by ID): # python download_document.py --document-id 202 ``` -------------------------------- ### Run Script to Upload Document to Specific Folder Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-upload-document/readme.md Use this command to upload a file directly to a specific folder within a workspace, providing the folder ID as an argument. ```bash $ python upload_document.py PATH_TO_FILE -f ID_OF_FOLDER ``` -------------------------------- ### Board Webhooks Source: https://context7.com/projectplace/api-code-examples/llms.txt Manage webhook subscriptions for card status changes on a ProjectPlace board. This includes subscribing, updating, and unsubscribing. ```APIDOC ## Subscribe to Card Status Change Events ### Description Subscribes a webhook to receive notifications for card status changes on a specific board. ### Method POST ### Endpoint /1/webhooks ### Parameters #### Path Parameters (None) #### Query Parameters (None) #### Request Body - **artifact_type** (string) - Required - The type of artifact, should be 'board'. - **artifact_id** (integer) - Required - The ID of the board to subscribe to. - **event_type** (array of strings) - Required - The events to subscribe to, e.g., ['card_status_change']. - **project_id** (integer) - Required - The ID of the project the board belongs to. - **webhook** (string) - Required - The URL to send webhook notifications to. ### Request Example ```json { "artifact_type": "board", "artifact_id": 42, "event_type": ["card_status_change"], "project_id": 99, "webhook": "https://my-server.example.com/webhook" } ``` ### Response #### Success Response (200) - **id** (integer) - The ID of the created webhook subscription. - **artifact_type** (string) - The type of artifact. - **artifact_id** (integer) - The ID of the artifact. - **webhook** (string) - The registered webhook URL. #### Response Example ```json { "id": 55, "artifact_type": "board", "artifact_id": 42, "webhook": "https://my-server.example.com/webhook", "event_type": ["card_status_change"] } ``` ## List Webhooks for a Board ### Description Retrieves a list of all configured webhooks and filters them for a specific board. ### Method GET ### Endpoint /1/webhooks/list ### Parameters (None) ### Response #### Success Response (200) - **id** (integer) - The ID of the webhook. - **artifact_id** (integer) - The ID of the artifact the webhook is associated with. - Other webhook details... #### Response Example ```json [ { "id": 55, "artifact_type": "board", "artifact_id": 42, "webhook": "https://my-server.example.com/webhook", "event_type": ["card_status_change"] } ] ``` ## Update Webhook URL ### Description Updates the URL and event types for an existing webhook subscription. ### Method PUT ### Endpoint /1/webhooks/{webhook_id}/update ### Parameters #### Path Parameters - **webhook_id** (integer) - Required - The ID of the webhook to update. #### Query Parameters (None) #### Request Body - **event_type** (array of strings) - Required - The events to subscribe to. - **webhook** (string) - Required - The new URL for the webhook. ### Request Example ```json { "event_type": ["card_status_change"], "webhook": "https://new-url.example.com/hook" } ``` ## Delete Webhook ### Description Deletes a specific webhook subscription. ### Method DELETE ### Endpoint /1/webhooks/{webhook_id} ### Parameters #### Path Parameters - **webhook_id** (integer) - Required - The ID of the webhook to delete. ### Request Example (None) ### Response #### Success Response (200) (Typically returns an empty body or a success confirmation) ``` -------------------------------- ### Run the Script Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-list-document-archive/readme.md Execute the Python script from your terminal. It will prompt for workspace ID and save the archive contents to a JSON file. ```bash $ python3 list_document_archive.py ``` -------------------------------- ### Delete User and Transfer Ownership with Python Source: https://context7.com/projectplace/api-code-examples/llms.txt Deletes a user account and transfers their owned items (workspaces, portfolios, etc.) to another user. Requires the user_id to delete and the replace_with_id for the new owner. ```python replace_with_id = 5678 requests.post( f'{API_ENDPOINT}/1/account/people/{user_id}', json={ 'action': 'delete_account_user', 'params': [{user_id: {'workspaces': {101: replace_with_id}, 'portfolios': {}, 'templates': {}, 'teams': {}}}] }, auth=oauth1 ).raise_for_status() ``` -------------------------------- ### Modify Authorization Attributes Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-enforce-column-name/readme.md Replace placeholder values with your actual application key, secret, and Robot account client credentials. ```python CLIENT_ID = 'REDACTED' CLIENT_SECRET = 'REDACTED' ``` -------------------------------- ### OData Download Completion Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-consume-odata/readme.md Indicates the completion of the OData download, showing the total downloaded size and the final compressed file name and size. ```text Done! Downloaded 5.86 MB to am_AccountWorkspaces_2023-10-30.json.gz (Final file size: 1.08 MB) ``` -------------------------------- ### Run Bulk Email Update Script Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-bulk-update-emails/readme.md Execute the Python script with a CSV file containing existing and new email addresses. The script processes these changes, prompts for confirmation, and reports on successful and failed updates. ```bash $ python3 bulk_update_account_emails.py changes.csv ``` -------------------------------- ### Run Script to Remove Inactive Users Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-remove-inactive-users/readme.md Execute the script with the number of inactive days and the ID of the new head administrator. The script will list inactive users and prompt for verification before removal. ```bash $ python3 remove_inactive_users.py DAYS NEW_HEAD_ADMIN_ID ``` -------------------------------- ### Bulk Update User Email Addresses with OAuth1 Source: https://context7.com/projectplace/api-code-examples/llms.txt Reads email change mappings from a CSV file, validates them against actual account members, and applies the changes using the `add_secondary_email` action. Requires OAuth1 credentials and a CSV file with `existing_email,new_email` pairs. ```python # examples/py-bulk-update-emails/bulk_update_account_emails.py # CSV format (no header row): old@company.com,new@company.com import csv import requests import requests_oauthlib API_ENDPOINT = 'https://api.projectplace.com' oauth1 = requests_oauthlib.OAuth1('APP_KEY', 'APP_SECRET', 'TOKEN_KEY', 'TOKEN_SECRET') # Load mappings from CSV def get_email_changes(csv_file): mapping = {} with open(csv_file, 'r') as f: for row in csv.DictReader(f, ['existing', 'new']): mapping[row['existing'].lower()] = row['new'].lower() return mapping # Validate against actual account members def get_valid_email_changes(existing_emails): users = requests.get(f'{API_ENDPOINT}/1/account/people', auth=oauth1).json() return { u['email'].lower(): {'id': int(u['id']), 'email': existing_emails[u['email'].lower()]} for u in users if u['email'].lower() in existing_emails and u['account_role'] in ( 'account_role_owner', 'account_role_co_owner', 'account_role_admin', 'account_role_member' ) } # Apply email change for a single user def change_email(user_id, new_email): r = requests.post( f'{API_ENDPOINT}/1/account/people/{user_id}', json={'action': 'add_secondary_email', 'params': [new_email]}, auth=oauth1 ) return r.json() # {"succeeded": ["123"], "failed": []} # CLI usage: # python bulk_update_account_emails.py email_changes.csv ``` -------------------------------- ### List Document Archive Contents Source: https://context7.com/projectplace/api-code-examples/llms.txt Retrieves and saves the JSON contents of a workspace's root document archive to a timestamped file. Uses OAuth1. ```python # examples/py-list-document-archive/list_document_archive.py import json, datetime, requests, requests_oauthlib API_ENDPOINT = 'https://api.projectplace.com' oauth1 = requests_oauthlib.OAuth1('APP_KEY', 'APP_SECRET', 'TOKEN_KEY', 'TOKEN_SECRET') # List accessible workspaces workspaces = requests.get(f'{API_ENDPOINT}/1/user/me/projects', auth=oauth1).json() workspace_id = workspaces[0]['id'] # pick the first, or prompt user # Fetch document archive contents contents = requests.get(f'{API_ENDPOINT}/2/documents/{workspace_id}', auth=oauth1).json() # { # "id": 1001, "container_id": 1001, "contents": [ # {"id": 201, "type": "Folder", "file_name": "Reports"}, # {"id": 202, "type": "Document", "file_name": "Q1_Summary.pdf", "os_file_name": "Q1_Summary.pdf"} # ] # } # Save to file filename = f'{workspace_id}-{datetime.datetime.now().isoformat(timespec="seconds")}.json' with open(filename, 'w') as fp: fp.write(json.dumps(contents, indent=2, sort_keys=True)) print(f'Saved to {filename}') # CLI usage (interactive workspace selection): # python list_document_archive.py ``` -------------------------------- ### Find Inactive Users with Python Source: https://context7.com/projectplace/api-code-examples/llms.txt Finds users who have been inactive for a specified number of days. Requires setting API_ENDPOINT and oauth1 authentication. ```python days = 90 from_dt = (datetime.datetime.utcnow() - datetime.timedelta(days=1825)).strftime('%Y-%m-%d') to_dt = (datetime.datetime.utcnow() - datetime.timedelta(days=days)).strftime('%Y-%m-%d') inactive = requests.post( f'{API_ENDPOINT}/1/account/people', json={ 'sort_by': '+last_login', 'filter': { 'last_logged_in': {'from': from_dt, 'to': to_dt}, 'account_roles': ['account_member', 'account_co_owner', 'account_administrator'] }, 'limit': 40, 'row_number': 0 }, auth=oauth1 ).json() print(f'Found {len(inactive)} inactive users') ``` -------------------------------- ### OAuth2 Authorization Code Flow with Python Source: https://context7.com/projectplace/api-code-examples/llms.txt Recommended for interactive user access, this flow opens a browser for user authorization and exchanges the returned code for access and refresh tokens. Use 'Bearer {access_token}' for subsequent API requests. ```Python # auth/py-oauth2-authorization-code/oauth2_authorization_code.py import random import requests import webbrowser from urllib.parse import urlencode CLIENT_ID = 'your_client_id' CLIENT_SECRET = 'your_client_secret' SUBDOMAIN = 'mycompany' REDIRECT_URI = 'https://oob' API_ENDPOINT = f'https://{SUBDOMAIN}.projectplace.com' # Step 1: Build authorization URL and open in browser auth_params = { 'client_id': CLIENT_ID, 'redirect_uri': REDIRECT_URI, 'state': f'random_{random.randint(1000000, 10000000)}' } auth_url = f'{API_ENDPOINT}/oauth2/authorize?{urlencode(auth_params)}' webbrowser.open(auth_url) cod = input('Enter the authorization code from the redirect URL: ') # Step 2: Exchange code for tokens tokens = requests.post( f'{API_ENDPOINT}/oauth2/access_token', data={ 'client_id': CLIENT_ID, 'client_secret': CLIENT_SECRET, 'code': cod, 'grant_type': 'authorization_code' } ).json() # {"access_token": "abc123...", "expires": 3600, "refresh_token": "xyz789..."} # Step 3: Use access token to call the API access_token = tokens['access_token'] user = requests.get( f'{API_ENDPOINT}/1/user/me/profile', headers={'Authorization': f'Bearer {access_token}'} ).json() print(f'Logged in as: {user["first_name"]} {user["last_name"]} ({user["email"]})') # Logged in as: Alice Smith (alice@mycompany.com) ``` -------------------------------- ### Unsubscribe from Board Events Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-board-webhooks/readme.md Use this command to delete an existing webhook subscription for a specific board. This stops the event notifications. ```bash $ python3 board_subscription.py BOARD_ID --unsubscribe ``` -------------------------------- ### Run Script to Enforce Column Name Source: https://github.com/projectplace/api-code-examples/blob/main/examples/py-enforce-column-name/readme.md Execute the script to rename a column at a specific position. The optional -o flag allows renaming only if the column currently has a specific name. ```bash $ python3 enforce_column_names.py COLUMN_POSITION NEW_NAME -o OPTIONAL_FROM_NAME ``` -------------------------------- ### Enforce Board Column Names Across Workspaces Source: https://context7.com/projectplace/api-code-examples/llms.txt Renames a board column across all active workspaces. Optionally filters by old column name. Requires OAuth2 Client Credentials and prompts for confirmation. ```python # examples/py-enforce-column-name/enforce_column_names.py import requests, requests.auth API_ENDPOINT = 'https://api.projectplace.com' CLIENT_ID = 'your_robot_client_id' CLIENT_SECRET = 'your_robot_client_secret' # Get access token access_token = requests.post( f'{API_ENDPOINT}/oauth2/access_token', data={'grant_type': 'client_credentials'}, auth=requests.auth.HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET) ).json()['access_token'] headers = {'Authorization': f'Bearer {access_token}'} # Paginate all active workspaces workspaces = requests.post( f'{API_ENDPOINT}/2/account/projects', json={'filter': {'archive_status': [0]}, 'limit': 100}, headers=headers ).json() # Get boards for a workspace boards = requests.get( f'{API_ENDPOINT}/1/projects/{workspaces[0]["id"]}/boards', headers=headers ).json() # Rename column at position 0 to "In Progress" on a board board = boards[0] column_order = 0 column_status_id = board['progresses'][column_order]['id'] requests.post( f'{API_ENDPOINT}/1/boards/{board["id"]}/statuses/{column_status_id}/properties', json={'name': 'In Progress'}, headers=headers ).raise_for_status() print(f'Renamed column 0 on board {board["id"]} to "In Progress"') # CLI usage: # python enforce_column_names.py 0 "In Progress" # python enforce_column_names.py 0 "In Progress" --old-column-name "Todo" ``` -------------------------------- ### Remove Inactive Users from Account Source: https://context7.com/projectplace/api-code-examples/llms.txt Identifies inactive users, their resources, and interactively confirms deletion or transfer of ownership. Uses OAuth1. ```python # examples/py-remove-inactive-users/remove_inactive_users.py import datetime, requests, requests_oauthlib API_ENDPOINT = 'https://api.projectplace.com' oauth1 = requests_oauthlib.OAuth1('APP_KEY', 'APP_SECRET', 'TOKEN_KEY', 'TOKEN_SECRET') ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.