### Example usage of Shortcut API functions Source: https://context7.com/useshortcut/api-cookbook/llms.txt Demonstrates how to use the API functions to fetch and process epics from the Shortcut API. ```python logging.basicConfig(level=logging.INFO) validate_environment() # This will automatically rate limit to avoid throttling all_epics = sc_get("/epics") for epic in all_epics: epic_details = sc_get(f"/epics/{epic['id']}") print(f"Epic: {epic_details['name']}") ``` -------------------------------- ### GET /api/beta/epics/{epic_id} Source: https://context7.com/useshortcut/api-cookbook/llms.txt Retrieve cycle time and lead time metrics for an epic and export them to a CSV file. This endpoint fetches epic statistics including average cycle time and lead time for reporting purposes. ```APIDOC ## GET /api/beta/epics/{epic_id} ### Description Retrieve cycle time and lead time metrics for an epic and export them to a CSV file in the Downloads folder. ### Method GET ### Endpoint /api/beta/epics/{epic_id} ### Parameters #### Path Parameters - **epic_id** (string) - Required - The unique identifier of the epic #### Query Parameters - **token** (string) - Required - API authentication token appended as query parameter #### Request Body None ### Request Example ```bash GET https://api.app.shortcut.com/api/beta/epics/54321?token=your_api_token ``` ### Response #### Success Response (200) - **name** (string) - The name of the epic - **stats.average_cycle_time** (number) - Average cycle time in seconds - **stats.average_lead_time** (number) - Average lead time in seconds #### Response Example ```json { "name": "Q4 Product Launch", "stats": { "average_cycle_time": 432000, "average_lead_time": 864000 } } ``` ### Error Responses - **401 Unauthorized** - Invalid or missing API token - **404 Not Found** - Epic with specified ID not found - **500 Internal Server Error** - Server error during processing ``` -------------------------------- ### Authenticate with Shortcut API using Python Source: https://context7.com/useshortcut/api-cookbook/llms.txt Shows how to retrieve the Shortcut API token from an environment variable, build the base URL, and perform an authenticated GET request. Uses the Requests library and includes error handling. Returns the JSON response for a specified endpoint and entity ID. ```Python import os # Set the environment variable (bash) # export SHORTCUT_API_TOKEN="your_token_here" # Access the token in Python shortcut_api_token = '?token=' + os.getenv('SHORTCUT_API_TOKEN') api_url_base = 'https://api.app.shortcut.com/api/beta' # Example: Making an authenticated request import requests import sys def get_api_response(endpoint, entity_id): try: url = api_url_base + endpoint + '/' + entity_id + shortcut_api_token response = requests.get(url) response.raise_for_status() except requests.exceptions.RequestException as e: print(e) sys.exit(1) return response.json() # Usage epic_endpoint = '/epics' epic_data = get_api_response(epic_endpoint, '12345') print(f"Epic name: {epic_data['name']}") ``` -------------------------------- ### GET /api/beta/objectives/{objective_id} Source: https://context7.com/useshortcut/api-cookbook/llms.txt Retrieve cycle time and lead time metrics for an objective to support reporting on organizational goals. This endpoint provides objective statistics including average cycle time and lead time. ```APIDOC ## GET /api/beta/objectives/{objective_id} ### Description Retrieve cycle time and lead time metrics for an objective to support reporting on organizational goals. ### Method GET ### Endpoint /api/beta/objectives/{objective_id} ### Parameters #### Path Parameters - **objective_id** (string) - Required - The unique identifier of the objective #### Query Parameters - **token** (string) - Required - API authentication token appended as query parameter #### Request Body None ### Request Example ```bash GET https://api.app.shortcut.com/api/beta/objectives/98765?token=your_api_token ``` ### Response #### Success Response (200) - **name** (string) - The name of the objective - **stats.average_cycle_time** (number) - Average cycle time in seconds - **stats.average_lead_time** (number) - Average lead time in seconds #### Response Example ```json { "name": "Q4 Product Launch", "stats": { "average_cycle_time": 432000, "average_lead_time": 864000 } } ``` ### Error Responses - **401 Unauthorized** - Invalid or missing API token - **404 Not Found** - Objective with specified ID not found - **500 Internal Server Error** - Server error during processing ``` -------------------------------- ### Identify and Archive Unused Labels - Python Setup Source: https://context7.com/useshortcut/api-cookbook/llms.txt Sets up the necessary imports for a script to identify and archive unused labels in Shortcut. This includes 'csv' for report generation and 'logging' for output messages. This snippet likely serves as a prelude to more complex label management logic. ```python import csv import logging ``` -------------------------------- ### GET /api/v2/search/stories Source: https://context7.com/useshortcut/api-cookbook/llms.txt Searches for stories based on query parameters like project and state. Used to fetch stories for sorting by due date. ```APIDOC ## GET /api/v2/search/stories ### Description Performs a search for stories with specified filters to retrieve a list for reordering. ### Method GET ### Endpoint /api/v2/search/stories ### Parameters #### Path Parameters None #### Query Parameters - **query** (string) - Required - Search query, e.g., 'project:50 state:500000044'. - **token** (string) - Required - API authentication token. #### Request Body None ### Request Example No body required. ### Response #### Success Response (200) - **data** (array of objects) - List of story objects with fields like id, deadline. #### Response Example { "data": [ { "id": 456, "deadline": "2023-12-31" } ] } ``` -------------------------------- ### GET /api/v2/labels Source: https://context7.com/useshortcut/api-cookbook/llms.txt Retrieves all labels in the Shortcut workspace. This endpoint is used to list labels and their associated stories and epics for identifying archivable labels. ```APIDOC ## GET /api/v2/labels ### Description Fetches a list of all labels in the workspace, including their IDs and names. ### Method GET ### Endpoint /api/v2/labels ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example No body required. ### Response #### Success Response (200) - **data** (array of objects) - List of label objects with fields like id, name. #### Response Example [ { "id": 123, "name": "Example Label" } ] ``` -------------------------------- ### Make rate-limited GET requests to Shortcut API Source: https://context7.com/useshortcut/api-cookbook/llms.txt Defines a function to make rate-limited GET requests to the Shortcut API with automatic error handling and JSON response parsing. ```python @rate_decorator(rate_mapping) def sc_get(path, params={}): """Make a rate-limited GET API call""" url = api_url_base + path logging.debug("GET url=%s params=%s" % (url, params)) resp = requests.get(url, headers=headers, params=params) resp.raise_for_status() return resp.json() ``` -------------------------------- ### GET /api/v2/labels/{id}/stories Source: https://context7.com/useshortcut/api-cookbook/llms.txt Retrieves all stories associated with a specific label. Used to check if a label has any incomplete stories before archiving. ```APIDOC ## GET /api/v2/labels/{id}/stories ### Description Gets stories linked to the specified label ID, allowing filtering for completed status. ### Method GET ### Endpoint /api/v2/labels/{id}/stories ### Parameters #### Path Parameters - **id** (integer) - Required - The label ID. #### Query Parameters None #### Request Body None ### Request Example No body required. ### Response #### Success Response (200) - **data** (array of objects) - List of story objects with fields like id, completed. #### Response Example [ { "id": 456, "completed": false } ] ``` -------------------------------- ### GET /api/v2/labels/{id}/epics Source: https://context7.com/useshortcut/api-cookbook/llms.txt Fetches epics associated with a given label. Helps determine if a label can be archived by checking for incomplete epics. ```APIDOC ## GET /api/v2/labels/{id}/epics ### Description Retrieves epics for the specified label to assess archivability. ### Method GET ### Endpoint /api/v2/labels/{id}/epics ### Parameters #### Path Parameters - **id** (integer) - Required - The label ID. #### Query Parameters None #### Request Body None ### Request Example No body required. ### Response #### Success Response (200) - **data** (array of objects) - List of epic objects with fields like id, completed. #### Response Example [ { "id": 789, "completed": true } ] ``` -------------------------------- ### Calculate Archivable Labels in Python Source: https://context7.com/useshortcut/api-cookbook/llms.txt Identifies labels in Shortcut that can be archived based on story and epic completion status. Requires authenticated GET requests via sc_get helper function. Returns list of labels with no stories/epics or only completed items. ```python def calculate_archivable_labels(include_completed): to_archive = [] logging.info("Fetching all labels with all associated stories & epics...") all_labels = sc_get("/labels") len_labels = len(all_labels) for idx, label in enumerate(all_labels): if idx % 10 == 0: logging.info("Progress: %.0f%%" % (100 * (idx + 1) / len_labels)) id = label["id"] label_stories = sc_get(f"/labels/{id}/stories") label_epics = sc_get(f"/labels/{id}/epics") no_stories = len(label_stories) == 0 no_epics = len(label_epics) == 0 if no_stories and no_epics: to_archive.append(label) continue if include_completed: incomplete_stories = [s for s in label_stories if not s["completed"]] incomplete_epics = [e for e in label_epics if not e["completed"]] if len(incomplete_stories) == 0 and len(incomplete_epics) == 0: to_archive.append(label) return to_archive ``` -------------------------------- ### Search Shortcut stories with pagination using Python Source: https://context7.com/useshortcut/api-cookbook/llms.txt Demonstrates searching for stories via the Shortcut API using query parameters and handling paginated responses to retrieve all matching results. Includes functions for initial search and subsequent page fetching, with error handling. Prints each story ID and name after aggregating all pages. ```Python import os import sys import requests shortcut_api_token = '?token=' + os.getenv('SHORTCUT_API_TOKEN') api_url_base = 'https://api.app.shortcut.com/api/beta' search_endpoint = '/search/stories' def search_stories(query): try: url = api_url_base + search_endpoint + shortcut_api_token response = requests.get(url, params=query) response.raise_for_status() except requests.exceptions.RequestException as e: print(e) sys.exit(1) return response.json() def paginate_results(next_page_data): try: url = 'https://api.app.shortcut.com' + next_page_data + '&token=' + os.getenv('SHORTCUT_API_TOKEN') response = requests.get(url) response.raise_for_status() except requests.exceptions.RequestException as e: print(e) sys.exit(1) return response.json() # Example: Search for incomplete stories with a specific label search_query = { 'query': '!is:done label:"Sprint"', 'page_size': 25 } pages_of_search_results = [] search_results = search_stories(search_query) # Collect all pages of results while search_results['next'] is not None: pages_of_search_results.append(search_results['data']) search_results = paginate_results(search_results['next']) else: pages_of_search_results.append(search_results['data']) # Process all stories for page in pages_of_search_results: for story in page: print(f"Story {story['id']}: {story['name']}") ``` -------------------------------- ### Set up API request headers and base URL Source: https://context7.com/useshortcut/api-cookbook/llms.txt Configures the base URL and required headers for Shortcut API requests, including authentication token and content type. ```python sc_token = os.getenv("SHORTCUT_API_TOKEN") api_url_base = "https://api.app.shortcut.com/api/v3" headers = { "Shortcut-Token": sc_token, "Accept": "application/json; charset=utf-8", "Content-Type": "application/json", "User-Agent": "shortcut-api-cookbook/0.0.1-alpha1", } ``` -------------------------------- ### Calculate Epic Cycle and Lead Times (Python) Source: https://context7.com/useshortcut/api-cookbook/llms.txt Retrieves cycle time and lead time metrics for a given epic ID using the Shortcut API. Extracts relevant data from the API response and writes it to a CSV file in the Downloads folder. Requires the 'shortcut_api_token' environment variable. ```Python import os import sys import requests shortcut_api_token = '?token=' + os.getenv('shortcut_api_token') api_url_base = 'https://api.app.shortcut.com/api/beta' epic_endpoint = '/epics' def get_api_response(endpoint, entity_id): try: url = api_url_base + endpoint + '/' + entity_id + shortcut_api_token response = requests.get(url) response.raise_for_status() except requests.exceptions.RequestException as e: print(e) sys.exit(1) return response.json() def epic_lead_cycle_times(get_epic_api_response): epic_stats = get_epic_api_response['stats'] epic_average_cycle_time = str(epic_stats['average_cycle_time']) epic_average_lead_time = str(epic_stats['average_lead_time']) epic_name = get_epic_api_response['name'] comma_separated_values = epic_name + ' ,' + epic_average_cycle_time + ' ,' + epic_average_lead_time return comma_separated_values def create_csv_with_epic_headers(document_name): named_csv_file = document_name + '.csv' csv_headers = 'Epic Title, Average Cycle Time, Average Lead Time' + '\n' with open(os.path.join(os.path.expanduser('~'), 'Downloads', named_csv_file), mode='a', encoding='utf-8') as f: f.write(csv_headers) return named_csv_file def write_to_csv(epic_name_cycle_lead_values, csv_document_name): with open(os.path.join(os.path.expanduser('~'), 'Downloads', csv_document_name), mode='a', encoding='utf-8') as f: f.write(epic_name_cycle_lead_values) # Example: Get metrics for epic with ID 54321 epic_id = '54321' document_name = 'epic_metrics_report' output_csv = create_csv_with_epic_headers(document_name) epic_response = get_api_response(epic_endpoint, epic_id) epic_output_details = epic_lead_cycle_times(epic_response) write_to_csv(epic_output_details, output_csv) print(f"{document_name}.csv is now in your Downloads folder.") ``` -------------------------------- ### Calculate Objective Cycle and Lead Times (Python) Source: https://context7.com/useshortcut/api-cookbook/llms.txt Retrieves cycle time and lead time metrics for a given objective ID using the Shortcut API. Extracts relevant data and prints the results to the console. Requires the 'SHORTCUT_API_TOKEN' environment variable. ```Python import os import sys import requests shortcut_api_token = '?token=' + os.getenv('SHORTCUT_API_TOKEN') api_url_base = 'https://api.app.shortcut.com/api/beta' objective_endpoint = '/objectives' def get_api_response(endpoint, entity_id): try: url = api_url_base + endpoint + '/' + entity_id + shortcut_api_token response = requests.get(url) response.raise_for_status() except requests.exceptions.RequestException as e: print(e) sys.exit(1) return response.json() def objective_lead_cycle_times(get_objective_api_response): stats = get_objective_api_response['stats'] objective_average_cycle_time = str(stats['average_cycle_time']) objective_average_lead_time = str(stats['average_lead_time']) objective_name = get_objective_api_response['name'] comma_separated_values = objective_name + ' ,' + objective_average_cycle_time + ' ,' + objective_average_lead_time return comma_separated_values # Example: Get metrics for objective with ID 98765 objective_id = '98765' objective_response = get_api_response(objective_endpoint, objective_id) objective_metrics = objective_lead_cycle_times(objective_response) print(f"Objective Metrics: {objective_metrics}") # Output: "Q4 Product Launch ,432000 ,864000" ``` -------------------------------- ### Configure rate limiting for Shortcut API requests Source: https://context7.com/useshortcut/api-cookbook/llms.txt Sets up rate limiting to stay within Shortcut's API limits (195 requests per minute with a 70-second max delay). Uses pyrate-limiter for in-memory rate limiting. ```python max_requests_per_minute = 200 rate = Rate(max_requests_per_minute - 5, Duration.MINUTE) bucket = InMemoryBucket([rate]) max_limiter_delay_seconds = 70 limiter = Limiter( bucket, raise_when_fail=True, max_delay=Duration.SECOND * max_limiter_delay_seconds ) ``` -------------------------------- ### Send Completed Stories to Slack - Python Source: https://context7.com/useshortcut/api-cookbook/llms.txt Searches for recently completed stories within a specified date range and project, then posts their details to a Slack channel using a webhook. It handles date calculations for the search range and formats the output for Slack. Requires 'requests' library and environment variable for API token. ```python from datetime import datetime, timedelta import os import sys import requests shortcut_api_token = '?token=' + os.getenv('shortcut_api_token') api_url_base = 'https://api.app.shortcut.com/api/beta' search_endpoint = '/search/stories' def date_range_for_search(): day_of_week = datetime.strftime(datetime.now(), '%A') yesterday = datetime.strftime(datetime.now() - timedelta(days=1), '%Y-%m-%d') today = datetime.strftime(datetime.now(), '%Y-%m-%d') if day_of_week == 'Monday': start_of_search_date_range = datetime.strftime(datetime.now() - timedelta(days=3), '%Y-%m-%d') else: start_of_search_date_range = yesterday return start_of_search_date_range, today def search_stories(query): try: url = api_url_base + search_endpoint + shortcut_api_token response = requests.get(url, params=query) response.raise_for_status() except requests.exceptions.RequestException as e: print(e) sys.exit(1) return response.json() def post_story_details_to_slack(story_details, slack_webhook): try: response = requests.post(slack_webhook, json=story_details) response.raise_for_status() except requests.exceptions.RequestException as e: print(e) sys.exit(1) return response.json() def parse_stories(stories_list, slack_webhook): for story in stories_list: story_details_for_slack = '' story_details_for_slack += story['name'] + ', ' + story['app_url'] + ', ' # Corrected access to 'app_url' tickets = story['external_tickets'] ticket_count = 0 if not tickets: story_details_for_slack += 'no tickets' else: for t in tickets: ticket_count += 1 story_details_for_slack += str(ticket_count) + ' tickets' output_for_slack = {'text': story_details_for_slack} post_story_details_to_slack(output_for_slack, slack_webhook) # Example: Send completed stories to Slack slack_webhook_url = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXX' start_of_date_range, end_of_date_range = date_range_for_search() date_range_for_completed_stories = 'completed:{}..{}'.format(start_of_date_range, end_of_date_range) search_query = {'query': date_range_for_completed_stories + ' project:"Mobile App"', 'page_size': 25} search_results = search_stories(search_query) parse_stories(search_results['data'], slack_webhook_url) print('Stories sent to Slack') # Slack receives: "Fix login bug, https://app.shortcut.com/story/12345, 3 tickets" ``` -------------------------------- ### Construct next page URL for Shortcut API using Python Source: https://github.com/useshortcut/api-cookbook/blob/main/Pagination.md This code extracts the 'next' pagination value from a previous API response and combines it with the base Shortcut API URL and an authentication token from the requires the os module for environment variable access and assumes the prior response is stored in a variable named results. The resulting next_url can be used to request the subsequent page of data. ```python shortcut_api_token = os.getenv('SHORTCUT_API_TOKEN') next_page = results['next'] next_url = 'https://api.app.shortcut.com' + next_page + '&token='+ shortcut_api_token ``` -------------------------------- ### Validate environment configuration Source: https://context7.com/useshortcut/api-cookbook/llms.txt Checks for required environment variables (SHORTCUT_API_TOKEN) and exits with an error message if not found. ```python def validate_environment(): """Validate SHORTCUT_API_TOKEN environment variable exists""" if sc_token is None: print("Error: You must define SHORTCUT_API_TOKEN environment variable", file=sys.stderr) sys.exit(1) ``` -------------------------------- ### Sort Stories by Due Date in JavaScript Source: https://context7.com/useshortcut/api-cookbook/llms.txt Fetches stories from a Shortcut project and sorts them by deadline. Stories without deadlines are placed at the end. Updates story priority order via API calls. Requires request-promise library. ```javascript const rp = require('request-promise') const getOptions = { uri: 'https://api.app.shortcut.com/api/v2/search/stories', json: true, qs: { token: 'YOUR_API_TOKEN', query: 'project:50 state:500000044' }, } const putOptions = { method: 'PUT', uri: '', qs: { token: 'YOUR_API_TOKEN' }, body: {}, json: true } rp(getOptions).then((searchResults) => { const stories = searchResults.data // Sort stories by deadline (due date) field stories.sort((a, b) => { if (!a.deadline) return 1 // Put stories with no deadlines later if (!b.deadline) return -1 return a.deadline < b.deadline ? -1 : 1 }) // Send priority order updates to Shortcut async function sendPriorityOrderUpdates() { for (let i = 1; i < stories.length; i++) { putOptions.uri = 'https://api.app.shortcut.com/api/v2/stories/' + stories[i].id putOptions.body.after_id = stories[i - 1].id await rp(putOptions) } } sendPriorityOrderUpdates() .then(() => console.log('Stories reordered successfully')) }).catch((error) => { console.log(error) }) ``` -------------------------------- ### Bulk update Shortcut story labels using Python Source: https://context7.com/useshortcut/api-cookbook/llms.txt Provides functions to replace an old label with a new one on multiple stories. Retrieves stories, constructs a new label list preserving existing labels, and sends PUT requests to update each story. Useful for sprint rollovers or label migrations. ```Python import os import sys import requests shortcut_api_token = '?token=' + os.getenv('SHORTCUT_API_TOKEN') api_url_base = 'https://api.app.shortcut.com/api/beta' stories_endpoint = '/stories' def change_story_labels(story_id, labels_on_story): url = api_url_base + stories_endpoint + '/' + story_id + shortcut_api_token params = {'labels': labels_on_story} response = requests.put(url, json=params) return response.json() def assess_story_labels(story_results, old_label, new_label): for story in story_results: story_id = str(story['id']) list_of_labels_on_story = story['labels'] list_of_labels_to_keep = [new_label] for label in list_of_labels_on_story: if label['name'] != old_label: list_of_labels_to_keep.append({'name': label['name']}) change_story(story_id, list_of_labels_to_keep) return None # Example: Replace "Sprint-23" with "Sprint-24" for incomplete stories existing_label = "Sprint-23" new_label = {'name': "Sprint-24", 'color': '#2ECC71'} ``` -------------------------------- ### Search for incomplete work by label - Python Source: https://github.com/useshortcut/api-cookbook/blob/main/change-label/README.md This code constructs a search query to find incomplete stories in Shortcut that have a specific label. The query uses search operators to exclude completed items and filter by label name. The search is configured to return 25 results per page and uses the !is:done operator to find incomplete work. ```python search_for_label_with_incomplete_work = {'query': '!is:done label:"' + existing_label + '"', 'page_size': 25} ``` -------------------------------- ### Archive Labels from CSV in Python Source: https://context7.com/useshortcut/api-cookbook/llms.txt Archives Shortcut labels by reading their IDs from a CSV file and making authenticated PUT requests. Requires sc_put helper function for API calls. Provides logging for each archived label. ```python def archive_labels(input_csv_file_name): with open(input_csv_file_name) as f: reader = csv.DictReader(f) for row in reader: label_id = row.get("id") logging.info(f"Archiving https://app.shortcut.com/settings/label/{label_id}") sc_put(f"/labels/{label_id}", {"archived": True}) ``` -------------------------------- ### Fetch and Write Epic Comments to CSV - Python Source: https://context7.com/useshortcut/api-cookbook/llms.txt Fetches comments for a given epic ID from the Shortcut API and writes them to a CSV file. It handles nested comments recursively and includes a timestamp in the output filename. Requires 'lib.py' for 'sc_get' and standard libraries like 'csv', 'datetime', and 'logging'. ```python from datetime import datetime import csv import logging # Assume sc_get is available from lib.py def sc_get(path): # Makes authenticated GET request to Shortcut API pass def write_epic_comment(writer, epic_comment, parent_id): csv_keys = ["id", "author_id", "text", "parent_id"] writer.writerow( {k: epic_comment[k] if k != "parent_id" else parent_id for k in csv_keys} ) nested_epic_comments = epic_comment["comments"] for nested_epic_comment in nested_epic_comments: write_epic_comment(writer, nested_epic_comment, epic_comment["id"]) def write_epic_comments(out_file, epic_comments): csv_keys = ["id", "author_id", "text", "parent_id"] writer = csv.DictWriter(out_file, fieldnames=csv_keys) writer.writeheader() for epic_comment in epic_comments: write_epic_comment(writer, epic_comment, None) def fetch_and_write_epic_comments(epic_id): epic_comments = sc_get(f"/epics/{epic_id}/comments") ts = datetime.now().strftime("%Y-%m-%dT%H:%M:%S") out_file_name = f"epic-{epic_id}-comments_{ts}.csv" logging.info(f"Writing CSV with epic comments to {out_file_name}") with open(out_file_name, "w") as f: write_epic_comments(f, epic_comments) # Example: Export comments for epic 12345 logging.basicConfig(level=logging.INFO) epic_id = "12345" fetch_and_write_epic_comments(epic_id) # Creates file: epic-12345-comments_2025-11-06T14:30:00.csv ``` -------------------------------- ### Define rate mapping for API requests Source: https://context7.com/useshortcut/api-cookbook/llms.txt Creates a rate mapping function that identifies API requests for rate limiting purposes. Returns a consistent identifier for all Shortcut API requests. ```python def rate_mapping(*args, **kwargs): return "shortcut-api-request", 1 rate_decorator = limiter.as_decorator() ``` -------------------------------- ### Write Labels to Archive in Python Source: https://context7.com/useshortcut/api-cookbook/llms.txt Exports a list of labels to a CSV file containing their ID, name, and app URL. Uses Python's csv.DictWriter with specified fieldnames. Useful for reviewing labels before archiving. ```python def write_labels_to_archive(out_file_name, labels): output_csv_keys = ["id", "name", "app_url"] with open(out_file_name, "w") as f: writer = csv.DictWriter(f, fieldnames=output_csv_keys) writer.writeheader() for label in labels: writer.writerow({k: label[k] for k in output_csv_keys}) ``` -------------------------------- ### Export Epic Comments to CSV (Python) Source: https://context7.com/useshortcut/api-cookbook/llms.txt Exports comments from an epic to a CSV file. This is a partial snippet and not complete. ```Python import csv import logging import sys from datetime import datetime ``` -------------------------------- ### Consolidate PivotalBlockers by Shortcut ID in Python Source: https://github.com/useshortcut/api-cookbook/blob/main/pivotal-import/post-import-utils/README.md This code consolidates PivotalBlocker objects using an OrderedMultiDict, filtering out epics and releases, mapping blockee IDs to Shortcut IDs, and skipping specific IDs (61265, 61257) to prevent duplicate story links. It depends on external objects like pe (likely a Pivotal exporter) and sm (Shortcut mapper). Inputs are blocker generators; outputs are a dictionary keyed by Shortcut IDs. Limitation: Hardcoded IDs may need updating for different datasets. ```python # Consolidate PivotalBlocker objects by Shortcut ID of 'blockee' in preparation for iterating over Shortcut stories md = OrderedMultiDict( ( scid, pb ) for pb in pe.gen_blockers() if pb.blockee_type not in { 'epic', 'release' } # All others become Shortcut stories if ( scid := sm.scid_from_ptid['story'].get(pb.blockee_id,None) ) if scid not in { 61265, 61257 } ) ``` -------------------------------- ### PUT /api/v2/stories/{id} Source: https://context7.com/useshortcut/api-cookbook/llms.txt Updates a story's position by setting the after_id to reorder stories based on priority or due date. ```APIDOC ## PUT /api/v2/stories/{id} ### Description Updates the priority order of a story relative to another by specifying the after_id. ### Method PUT ### Endpoint /api/v2/stories/{id} ### Parameters #### Path Parameters - **id** (integer) - Required - The story ID to update. #### Query Parameters - **token** (string) - Required - API authentication token. #### Request Body - **after_id** (integer) - Required - ID of the story that this one should follow. ### Request Example { "after_id": 123 } ### Response #### Success Response (200) - **data** (object) - Updated story object. #### Response Example { "id": 456, "after_id": 123 } ``` -------------------------------- ### PUT /api/v2/labels/{id} Source: https://context7.com/useshortcut/api-cookbook/llms.txt Updates a label, such as archiving it by setting the archived field to true. Used in batch operations to archive unused labels. ```APIDOC ## PUT /api/v2/labels/{id} ### Description Archives or updates properties of a specific label. ### Method PUT ### Endpoint /api/v2/labels/{id} ### Parameters #### Path Parameters - **id** (integer) - Required - The label ID. #### Query Parameters None #### Request Body - **archived** (boolean) - Required - Set to true to archive the label. ### Request Example { "archived": true } ### Response #### Success Response (200) - **data** (object) - Updated label object. #### Response Example { "id": 123, "archived": true } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.