### User Authentication: Authorization Request Source: https://developers.mural.co/public/docs/oauth Redirect users to Mural's authorization server to initiate the OAuth2 flow. This involves a GET request with specific query parameters. ```APIDOC ## Authenticate users: Authorization Request To authenticate a new user, your app must redirect them to `app.mural.co` with specific identifying information. You’ll redirect the user via their browser with a `GET` method. ### Method GET ### Endpoint `https://app.mural.co/api/public/v1/authorization/oauth2/` ### Parameters #### Query Parameters - **client_id** (string) - Required - The client identifier for your app. - **redirect_uri** (string) - Required - The URI to which the user will be redirected after authorization. Must be a pre-registered Redirect URL. - **scope** (string) - Required - A space-delimited list of requested permissions (e.g., `room:read room:write`). - **state** (string) - Optional - A randomly generated value to maintain state between the request and callback. - **response_type** (string) - Required - Must be `code` for the authorization code flow. ### Request Example `GET https://app.mural.co/api/public/v1/authorization/oauth2/?client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI&scope=room:read&state=YOUR_STATE&response_type=code` ### Response #### Success Response (Redirect) After the user authorizes the app, they are redirected to the `redirect_uri` with a `code` and `state` parameter. Example callback: `https://your-redirect-uri.com/callback?code=AUTHORIZATION_CODE&state=YOUR_STATE` #### Callback Parameters - **code** (string) - The authorization code that can be exchanged for an access token. - **state** (string) - The state variable provided in the initial request, if applicable. ``` -------------------------------- ### Mural Authorization Request Source: https://developers.mural.co/public/docs/oauth Redirect users to Mural's authorization server to initiate the OAuth2 flow. This GET request requires your client ID, redirect URI, desired scope, and an optional state parameter. ```http GET https://app.mural.co/api/public/v1/authorization/oauth2/? client_id=:client_id& redirect_uri=:callback& scope=:scope& state=:state& response_type=code ``` -------------------------------- ### Express OAuth Server for Authorization and Token Handling (JavaScript) Source: https://developers.mural.co/public/docs/basic-oauth-server-setup This JavaScript code sets up an Express.js server to handle OAuth 2.0 flows. It includes endpoints for initiating authorization requests, exchanging authorization codes for access tokens, and refreshing access tokens using a refresh token. Dependencies include `axios`, `cookie-parser`, and `express`. It takes client credentials, redirect URIs, and scopes as configuration. ```javascript const axios = require("axios"); const cookieParser = require('cookie-parser'); const express = require("express"); const app = express(); app.use(express.json()); app.use(cookieParser()); const API_BASE = "https://app.mural.co"; const config = { clientId: "my_mural_client_id", // replace this value with your app's client ID clientSecret: "my_mural_client_secret", // replace this value with your app's client secret redirectUri: "http://localhost:5000/auth/token/", // this should point back to this express server scopes: [ // put any scopes you are using in here "murals:read", "murals:write", "rooms:read", "workspaces:read", "identity:read", ], serverPort:5000, authorizationUri: `${API_BASE}/api/public/v1/authorization/oauth2/`, accessTokenUri: `${API_BASE}/api/public/v1/authorization/oauth2/token`, refreshTokenUri: `${API_BASE}/api/public/v1/authorization/oauth2/refresh`, }; /** * If someone has not been authenticated, you can request a url from this endpoint to redirect them to * first. You can optionally pass a `state` query parameter and a `redirectUri` query parameter. * @param state * @param redirectUri */ app.get( "/auth", /** * * @param {import('express').Request} req * @param {import('express').Response} res */ (req, res) => { // decide where we are redirecting after being authenticated. const redirectUri = req.query.redirectUri ? req.query.redirectUri.toString() : undefined; // is there any state that needs to be passed through the auth process const state = req.query.state ? req.query.state.toString() : undefined; const query = new URLSearchParams(); query.set("client_id", config.clientId); query.set("redirect_uri", config.redirectUri); query.set("response_type", "code"); if (state) { query.set("state", state); } if (config.scopes && config.scopes.length) { query.set("scope", config.scopes.join(" ")); } // This will return a url string that will allow you to authenticate your app // and it can also redirect back to your client application res.cookie('redirectUri', redirectUri) res.redirect(302, `${config.authorizationUri}?${query}`); } ); app.get( '/auth/token', /** * * @param {import('express').Request} req * @param {import('express').Response} res */ async ( req, res, ) => { const redirectUrl = new URL(req.cookies.redirectUri || req.protocol+'://'+req.hostname+'/'); console.log(req.cookies.redirectUri, redirectUrl.href); const payload = { data: { client_id: config.clientId, client_secret: config.clientSecret, code: req.query.code, grant_type: 'authorization_code', redirect_uri: req.query.redirectUri || config.redirectUri, }, method: 'POST', url: config.accessTokenUri }; const response = await axios.request(payload); if (response.status !== 200) { throw 'token request failed'; } redirectUrl.searchParams.set('accessToken',response.data.access_token); redirectUrl.searchParams.set('refreshToken', response.data.refresh_token); res.redirect(302, redirectUrl.href); }, ); app.post( '/auth/refresh', /** * * @param {import('express').Request} req * @param {import('express').Response} res */ async (req, res) => { const payload= { data: { client_id: config.clientId, client_secret: config.clientSecret, grant_type: 'refresh_token', refresh_token: req.body.refreshToken, scope: config.scopes, }, method: 'POST', url: config.refreshTokenUri, }; const response = await axios.request(payload); if (response.status !== 200) { throw 'refresh token request failed'; } res.json({ accessToken: response.data.access_token, refreshToken: response.data.refresh_token, }); }, ); app.listen(config.serverPort, ()=>{ console.log(`Example app listening at http://localhost:${config.serverPort}`); }); ``` -------------------------------- ### Client Application Rate Limit Headers - JSON Source: https://developers.mural.co/public/docs/rate-limiting Example JSON response headers for client application-specific rate limiting. These follow a similar pattern to user headers but include an 'App-' prefix. ```json { "X-RateLimit-App-Limit": "10000", "X-RateLimit-App-Remaining": "9999", "X-RateLimit-App-Reset": "1627319309" } ``` -------------------------------- ### Mural API Call with Access Token Source: https://developers.mural.co/public/docs/oauth Make authenticated requests to the Mural API by including the obtained access token in the Authorization Bearer header. This example shows how to fetch workspaces. ```sh curl -sH 'Authorization: Bearer ' 'https://app.mural.co/api/public/v1/workspaces' ``` -------------------------------- ### User Rate Limit Headers - JSON Source: https://developers.mural.co/public/docs/rate-limiting Example JSON response headers for user-specific rate limiting. These indicate the total limit, remaining requests, and the timestamp for when the limit resets. ```json { "X-RateLimit-Limit": "25", "X-RateLimit-Remaining": "24", "X-RateLimit-Reset": "1627319309" } ``` -------------------------------- ### GET /api/public/{version}/workspaces/{workspaceId}/murals Source: https://developers.mural.co/public/docs/getworkspacemurals Retrieves all murals for a given workspace that the authenticated user has access to. Requires `murals:read` authorization scope. ```APIDOC ## GET /api/public/{version}/workspaces/{workspaceId}/murals ### Description Retrieves all murals that the authenticated user owns or is a member of for a specific workspace. ### Method GET ### Endpoint https://app.mural.co/api/public/{version}/workspaces/{workspaceId}/murals ### Parameters #### Path Parameters - **version** (string) - Required - The API version (e.g., 'v1'). - **workspaceId** (string) - Required - The ID of the workspace. #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) - **murals** (array) - A list of mural objects. - **id** (string) - The ID of the mural. - **name** (string) - The name of the mural. - **description** (string) - The description of the mural. - **createdAt** (string) - The creation timestamp of the mural. - **updatedAt** (string) - The last updated timestamp of the mural. #### Response Example ```json { "murals": [ { "id": "mural123", "name": "Project Brainstorm", "description": "Initial ideas for the new project.", "createdAt": "2023-10-27T10:00:00Z", "updatedAt": "2023-10-27T11:30:00Z" }, { "id": "mural456", "name": "Team Retrospective", "description": "Weekly team retrospective meeting.", "createdAt": "2023-10-26T14:00:00Z", "updatedAt": "2023-10-26T15:00:00Z" } ] } ``` ### Authorization Requires `murals:read` scope with OAuth2 authentication. ``` -------------------------------- ### Example JSON Response for Paginated Endpoint Source: https://developers.mural.co/public/docs/pagination This JSON structure represents a typical response from a paginated API endpoint. It includes a 'value' field containing a list of items and a 'next' field with a token for retrieving the subsequent page of results. If no more pages are available, the 'next' field will be absent. ```json { "value": [ { "id": "1", "name": "Workspace 1" }, ... { "id": "100", "name": "Workspace 100" } ], "next": "" } ``` -------------------------------- ### Mural API Authorization Error Responses (JSON) Source: https://developers.mural.co/public/docs/oauth This snippet provides examples of common JSON error responses that can occur during Mural API authorization requests, such as invalid requests, incorrect client credentials, invalid grants, and unsupported grant types. ```json { "error": "invalid_request", "error_description": "The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed." } ``` ```json { "error": "invalid_client", "error_description": "Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method." } ``` ```json { "error": "invalid_grant", "error_description": "The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client." } ``` ```json { "error": "unsupported_grant_type", "error_description": "The authorization grant type is not supported." } ``` -------------------------------- ### Exceeded Client Application Limit Response - JSON Source: https://developers.mural.co/public/docs/rate-limiting Example JSON response body when the client application rate limit is exceeded. It includes limit, remaining, reset timestamp, and the application type identifier. ```json { "limit": 10000, "remaining": 0, "reset": 1627319309, "type": "app:7b0316214e04-0a89-d284-1763-da46236c" } ``` -------------------------------- ### Preview Version Usage Source: https://developers.mural.co/public/docs/versioning How to access and use the preview version of APIs for testing. ```APIDOC ## Preview API Version ### Description A preview version of APIs is available for developers to test new endpoints. These should not be used in production environments. ### Accessing Preview Endpoints - Use the `Accept` header in your request: `vnd.mural.preview`. ``` -------------------------------- ### Consume Mural API using Python Source: https://developers.mural.co/public/docs/python-example This Python script demonstrates how to authenticate with the Mural API using OAuth 2.0, fetch a list of workspaces, and create multiple murals within a specified room. It requires `client_id`, `client_secret`, and `roomId` to be set, and relies on the `requests-oauthlib` and `requests-toolbelt` libraries. The script includes a local HTTP server to handle the OAuth redirect. ```python from requests_oauthlib import OAuth2Session from oauthlib.oauth2 import TokenExpiredError from http.server import HTTPServer, BaseHTTPRequestHandler import time import http from requests_toolbelt.utils import dump import webbrowser; import json; class ServerHandler(BaseHTTPRequestHandler): def do_GET(self): self.send_response(200) self.end_headers() self.server.auth_response = self.requestline[4:-9] # HTTP server for manage redirects httpd = HTTPServer(('127.0.0.1', 8000), ServerHandler) # Redirect URI # Check this URL is part of the `redirect URLs` of your APP. redirect_uri = 'http://127.0.0.1:8000/' # Credentials of your APP client_id = 'YOUR_CLIENT_ID' client_secret = 'YOUR_CLIENT_SECRET' # Room ID where murals will be created oomId = 1111111111111111 # Mural OAuth2 endpoints authorization_base_url = "https://app.mural.co/api/public/v1/authorization/oauth2/" token_url = "https://app.mural.co/api/public/v1/authorization/oauth2/token" refresh_url = "https://app.mural.co/api/public/v1/authorization/oauth2/refresh" # Scopes required by the APP scopes = [ "murals:read", "murals:read", "murals:write", "rooms:read", "rooms:write", "templates:read", "templates:write", "workspaces:read", "users:read", "workspaces:write" ] mural = OAuth2Session(client_id, scope=scopes, redirect_uri=redirect_uri) # Redirect user to app.mural.co for authorization authorization_url, state = mural.authorization_url(authorization_base_url) # Open the web browser to the authorization URL. # User will be asked to login and authorize the APP webbrowser.open(authorization_url); httpd.handle_request() # Get the authorization code from the callback url redirect_response = "https://127.0.0.1:8000" + httpd.auth_response # Get the access token token = mural.fetch_token(token_url, client_secret=client_secret, authorization_response=redirect_response) # Start calling Mural API endpoints # Get the list of workspaces print('\nGet the list of workspaces:\n') res = mural.get('https://app.mural.co/api/public/v1/workspaces') workspaces = res.json().get("value"); print(json.dumps(workspaces, indent=4)) # Create 5 murals inside a room print('\nCreate 5 murals inside a room:') for i in range(1, 6): title = f"Mural {i} via API" # POST the title and roomId to create a new Mural res = mural.post("https://app.mural.co/api/public/v1/murals", json={"title": title, "roomId": roomId}); newMural = res.json().get("value"); print(f'\n{title}') print(json.dumps(newMural, indent=4)) # If you need to refresh the token # mural.scope = None # mural.refresh_token(refresh_url, client_id=client_id, client_secret=client_secret) ``` -------------------------------- ### Public API Versioning Source: https://developers.mural.co/public/docs/versioning Details on how the public Mural API is versioned and how to specify the version in the endpoint URL. ```APIDOC ## Public Mural API Versioning ### Description The public Mural API is versioned using a "major version" scheme, indicated by a 'v' followed by an integer (e.g., v1, v2). ### Versioning Scheme - The version number is included in the URL: `https://app.mural.co/api/public/{version}`. - Example for v1: `https://app.mural.co/api/public/v1/workspaces`. - Mural supports two versions: the current and the previous one. ### Breaking Changes - Defined as changes that remove or alter existing elements or actions. - Examples include removing parameters, adding required fields without defaults, changing field types, removing endpoints, or changing HTTP methods. ### Non-breaking Changes - Defined as changes that add functionality without affecting existing operations. - Examples include adding response fields, new endpoints, new sorting/filtering strategies, or removing redundant headers. ### New Versions - When a new version is released, previous versions remain available for a period. - Mural aims to provide advance notice of breaking changes. ``` -------------------------------- ### Upload File to Storage Source: https://developers.mural.co/public/docs/how-to-upload-a-file-to-a-mural Uploads a file to the storage using the URL and headers obtained from the 'Create Asset URL' step. ```APIDOC ## PUT [URL from Create Asset URL] ### Description Uploads the actual file content to the storage location provided by the asset URL. ### Method PUT ### Endpoint [URL provided in the response of POST /api/public/v1/murals/{muralId}/assets] ### Parameters #### Headers - **x-ms-blob-type** (string) - Required - The blob type, typically 'BlockBlob', obtained from the response headers of the 'Create Asset URL' endpoint. #### Request Body - **(binary)** - Required - The file content to be uploaded. ### Request Example ```shell curl --request PUT 'https://url:443/uploads/workspace1234/jD6Qzs6lSHy2bHAwFfCrjqU9RL3vCxFgYVl2nQrUYA.pdf?se=2057-04-01T19%3A27%3A52Z&sp=c&sv=2018-03-28&sr=b&sig=Jh...qYQ%3D' \ --header 'x-ms-blob-type: BlockBlob' \ --data-binary '@/Users/testuser/jD6Qzs6lSHy2bHAwFfCrjqU9RL3vCxFgYVl2nQrUYA.pdf' ``` ### Response #### Error Response (403) - **Error**: This request is not authorized to perform blob overwrites. (Occurs if attempting to upload to the same URL multiple times). ``` -------------------------------- ### Pagination and Page Size Source: https://developers.mural.co/public/docs/pagination This section details how to retrieve paginated data from API endpoints. It explains the use of the 'next' token to fetch subsequent pages and the 'limit' query parameter to control the number of items returned per page. ```APIDOC ## Pagination and Page Size ### Description API calls that return lists of items may have a large number of results. Instead of returning all the results at once, a single page of results is returned along with information on how to retrieve the next page. This strategy is called pagination. When calling a paginated endpoint, the response contains a list of items in the `value` field and a token to get the next page of items in the `next` field. ### Request Example (Fetching data) ```json { "value": [ { "id": "1", "name": "Workspace 1" }, ... { "id": "100", "name": "Workspace 100" } ], "next": "" } ``` ### Retrieving the Next Page To retrieve the next page, pass the value of `next` as a query parameter. ### Method GET ### Endpoint `/api/public/v1/workspaces?next=` ### Query Parameters - **next** (string) - Required - A token to retrieve the next page of items. ### Response Example (Next Page Available) ```json { "value": [ { "id": "101", "name": "Workspace 101" }, ... ], "next": "" } ``` ### Response Example (No More Pages) When no more pages are available, the `next` field does not appear in the response. ```json { "value": [ { "id": "201", "name": "Workspace 201" } ] } ``` ### Page Size Control Each resource type has its own default page size (e.g., 100 or fewer). You can limit the number of results returned per page using the `limit` query parameter. ### Method GET ### Endpoint `/api/public/v1/workspaces?limit=10` ### Query Parameters - **limit** (integer) - Optional - The maximum number of results to return per page. ### Request Example (Limited Results) ```http GET /api/public/v1/workspaces?limit=10 ``` ### Subsequent Requests with Limit Each subsequent request to retrieve remaining pages must specify the same value for `limit`. ### Method GET ### Endpoint `/api/public/v1/workspaces?limit=10&next=` ### Query Parameters - **limit** (integer) - Optional - The maximum number of results to return per page. - **next** (string) - Required - A token to retrieve the next page of items. ### Request Example (Limited Results with Next Token) ```http GET /api/public/v1/workspaces?limit=10&next= ``` ``` -------------------------------- ### Enterprise API Versioning Source: https://developers.mural.co/public/docs/versioning Information on how Enterprise APIs are versioned separately from the public API. ```APIDOC ## Enterprise API Versioning ### Description Mural's Enterprise APIs follow a versioning scheme similar to the public API, but each Enterprise API increments its version numbers independently. ``` -------------------------------- ### Automating Refresh Token Workflow with Postman Variables Source: https://developers.mural.co/public/docs/testing-with-postman This section details how to automate the refresh token process in Postman by using environment variables and pre-request scripts. ```APIDOC ## Automating Refresh Token workflow using variables ### Description This guide explains how to set up Postman environment variables and use a script in the 'Tests' tab to automatically update your refresh token. This ensures that your refresh token is always current when you call the refresh token endpoint. ### Setup Steps: 1. **Create an Environment Variable:** * Click the **Environment quick look** button (eye icon) in the top-right corner of Postman. * Click **Edit** for your active environment. * Add a new variable named `refresh_token`. * Enter your current refresh token value in both the **Initial Value** and **Current Value** fields. * Click **Save**. 2. **Update the Refresh Token Request:** * Open your **Refresh Token** request. * Navigate to the **Body** tab. * Replace the hardcoded `refresh_token_value` with your environment variable syntax: `{{refresh_token}}`. 3. **Add a Test Script:** * In the same **Refresh Token** request, open the **Tests** tab. * Paste the following JavaScript code: ```javascript const reqBody = JSON.parse(pm.request.body.raw); pm.environment.set("refresh_token", pm.response.json().refresh_token); ``` * Click **Save**. ### How it works: When you send the request: 1. The request body uses the `{{refresh_token}}` variable, fetching its current value from your environment. 2. Upon a successful response, the script in the **Tests** tab parses the response JSON. 3. It then extracts the `refresh_token` from the response and uses `pm.environment.set()` to update the `refresh_token` environment variable with this new value. **Note:** The `pm.environment.set()` command requires the variable to be defined as an environment variable. It will not work for collection or global variables. ``` -------------------------------- ### Create an image widget on a mural Source: https://developers.mural.co/public/docs/how-to-upload-an-image-to-a-mural Creates an image widget on a specified mural using the asset name obtained from the 'Create an asset URL' step. This endpoint allows customization of the widget's position, size, and appearance. ```APIDOC ## POST /api/public/v1/murals//widgets/image ### Description Creates an image widget on a mural using the uploaded image asset. ### Method POST ### Endpoint `/api/public/v1/murals//widgets/image` ### Parameters #### Path Parameters - **muralId** (string) - Required - The ID of the mural where the widget will be created. #### Request Body - **name** (string) - Required - The name of the asset (file path in storage) from the 'Create an asset URL' step. - **x** (number) - Required - The x-coordinate for the widget's position. - **y** (number) - Required - The y-coordinate for the widget's position. - **width** (number) - Required - The width of the widget. - **height** (number) - Required - The height of the widget. - **border** (boolean) - Optional - Whether to display a border for the widget. - **presentationIndex** (number) - Optional - The z-index for the widget. - **rotation** (number) - Optional - The rotation angle of the widget. - **showCaption** (boolean) - Optional - Whether to show the caption for the widget. ### Request Example ```json { "name": "workspace1234/jD6Qzs6lSHy2bHAwFfCrjqU9RL3vCxFgYVl2nQrUYA.png", "x":350, "y":370, "width": 600, "height": 600, "border": true, "presentationIndex": 0, "rotation": 0, "showCaption": false } ``` ### Response #### Success Response (201) Indicates that the image widget was successfully created on the mural. #### Error Response - Appropriate error responses will be returned for invalid inputs or issues during widget creation. ``` -------------------------------- ### Create File Widget on Mural API Source: https://developers.mural.co/public/docs/how-to-upload-a-file-to-a-mural Creates a file widget on a mural using the previously uploaded file. ```APIDOC ## POST /api/public/v1/murals/{muralId}/widgets/file ### Description Creates a file widget on a specified mural, referencing the uploaded file. ### Method POST ### Endpoint /api/public/v1/murals/{muralId}/widgets/file ### Parameters #### Path Parameters - **muralId** (string) - Required - The ID of the mural where the file widget will be created. #### Request Body - **name** (string) - Required - The name of the file as generated in the 'Create Asset URL' step (e.g., "workspace1234/your-file.pdf"). - **x** (integer) - Required - The x-coordinate for the widget's position. - **y** (integer) - Required - The y-coordinate for the widget's position. - **width** (integer) - Optional - The width of the widget. Defaults to 600. - **height** (integer) - Optional - The height of the widget. Defaults to 600. - **presentationIndex** (integer) - Optional - The z-index of the widget. Defaults to 0. - **rotation** (integer) - Optional - The rotation of the widget in degrees. Defaults to 0. ### Request Example ```json { "name": "workspace1234/jD6Qzs6lSHy2bHAwFfCrjqU9RL3vCxFgYVl2nQrUYA.pdf", "x":350, "y":370, "width": 600, "height": 600, "presentationIndex": 0, "rotation": 0 } ``` ### Response #### Success Response (201) Indicates the file widget was successfully created on the mural. The response body typically contains the details of the created widget. ``` -------------------------------- ### Upload File to Storage using cURL Source: https://developers.mural.co/public/docs/how-to-upload-a-file-to-a-mural Demonstrates uploading a file to the generated asset URL. This cURL command uses a PUT request with specific headers and the file data. Ensure you use the correct URL and headers received from the 'Create an asset URL' step. ```shell curl --request PUT 'https://url:443/uploads/workspace1234/jD6Qzs6lSHy2bHAwFfCrjqU9RL3vCxFgYVl2nQrUYA.pdf?se=2057-04-01T19%3A27%3A52Z&sp=c&sv=2018-03-28&sr=b&sig=Jh...qYQ%3D' \ --header 'x-ms-blob-type: BlockBlob' \ --data-binary '@/Users/testuser/jD6Qzs6lSHy2bHAwFfCrjqU9RL3vCxFgYVl2nQrUYA.pdf' ``` -------------------------------- ### HTTP Request for Next Page with Limited Results Source: https://developers.mural.co/public/docs/pagination This HTTP request illustrates how to retrieve the next page of data while maintaining a specific page size. It combines the 'limit' query parameter with the 'next' token to ensure consistent result counts across paginated calls. ```http GET /api/public/v1/workspaces?limit=10&next= ``` -------------------------------- ### Create an asset URL Source: https://developers.mural.co/public/docs/how-to-upload-an-image-to-a-mural This endpoint is used to generate a pre-signed URL for uploading an image to storage. It requires the mural ID and the file extension of the image. ```APIDOC ## POST /api/public/v1/murals//assets ### Description Creates a pre-signed URL for uploading an image to storage. ### Method POST ### Endpoint `/api/public/v1/murals//assets` ### Parameters #### Path Parameters - **muralId** (string) - Required - The ID of the mural. #### Request Body - **fileExtension** (string) - Required - The extension of the file to be uploaded (e.g., 'png'). ### Request Example ```json { "fileExtension": "png" } ``` ### Response #### Success Response (200) - **value** (object) - Contains upload details. - **url** (string) - The URL to upload the image to. - **name** (string) - The name of the asset in storage. - **headers** (object) - Headers required for the upload. #### Response Example ```json { "value": { "url": "https://url:443/uploads/workspace1234/jD6Qzs6lSHy2bHAwFfCrjqU9RL3vCxFgYVl2nQrUYA.png?se=2057-04-01T19%3A27%3A52Z&sp=c&sv=2018-03-28&sr=b&sig=Jh...qYQ%3D", "name": "workspace1234/jD6Qzs6lSHy2bHAwFfCrjqU9RL3vCxFgYVl2nQrUYA.png", "headers": { "x-ms-blob-type": "BlockBlob" } } } ``` #### Error Response (400) - **code** (string) - Error code, e.g., 'ASSET_TYPE_FORBIDDEN'. - **message** (string) - Description of the error. ``` -------------------------------- ### Using the OAuth Token Source: https://developers.mural.co/public/docs/oauth Access Mural API resources by including the obtained access token in the Authorization header as a Bearer token. ```APIDOC ## Use the OAuth Token Once you have the user access token, you can call the API by passing it in the `Authorization` header. ### Method Any (e.g., GET, POST, PUT, DELETE) ### Endpoint Any Mural API endpoint ### Headers - **Authorization**: Bearer ### Request Example ```sh curl -sH 'Authorization: Bearer ' 'https://app.mural.co/api/public/v1/workspaces' ``` ``` -------------------------------- ### Upload Image to Storage using PUT Request (cURL) Source: https://developers.mural.co/public/docs/how-to-upload-an-image-to-a-mural This code snippet shows how to upload an image file to the storage location obtained from the 'Create Asset URL' step. It uses a PUT request with the provided URL and headers, and the `--data-binary` flag to send the file content. ```shell curl --request PUT \ --header 'x-ms-blob-type: ' \ --data-binary ``` ```shell curl --request PUT 'https://url:443/uploads/workspace1234/jD6Qzs6lSHy2bHAwFfCrjqU9RL3vCxFgYVl2nQrUYA.png?se=2057-04-01T19%3A27%3A52Z&sp=c&sv=2018-03-28&sr=b&sig=Jh...qYQ%3D' \ --header 'x-ms-blob-type: BlockBlob' \ --data-binary '@/Users/testuser/jD6Qzs6lSHy2bHAwFfCrjqU9RL3vCxFgYVl2nQrUYA.png' ``` -------------------------------- ### Create Asset URL for Image Upload (cURL) Source: https://developers.mural.co/public/docs/how-to-upload-an-image-to-a-mural This snippet demonstrates how to create a temporary asset URL for uploading an image to Mural storage. It requires a mural ID and an authorization token. The response provides a secure URL and necessary headers for the subsequent upload. ```shell curl --request POST \ --url https://app.mural.co/api/public/v1/murals//assets \ --header 'Authorization: Bearer ' --header 'Content-Type: application/json' \ --data \ '{ "fileExtension": "png" }' ``` -------------------------------- ### Create Asset URL using cURL Source: https://developers.mural.co/public/docs/how-to-upload-a-file-to-a-mural This snippet shows how to create a unique asset URL for uploading files to a Mural board. It requires your mural ID and an authentication token. The response provides a temporary URL for storage upload and metadata. ```shell curl --request POST \ --url https://app.mural.co/api/public/v1/murals//assets \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data \ '{ "fileExtension": "pdf" }' ``` -------------------------------- ### Upload an image to storage Source: https://developers.mural.co/public/docs/how-to-upload-an-image-to-a-mural Uploads an image file to the pre-signed URL obtained from the 'Create an asset URL' step. This is typically done using a PUT request with the image data. ```APIDOC ## PUT ### Description Uploads an image file to the storage using the URL and headers provided by the 'Create an asset URL' endpoint. ### Method PUT ### Endpoint `` (Received from Create an asset URL response) ### Parameters #### Headers - **x-ms-blob-type** (string) - Required - The blob type, typically 'BlockBlob' (from Create an asset URL response headers). #### Request Body - **file** (binary) - Required - The path to the image file to be uploaded. ### Request Example ```shell curl --request PUT 'https://url:443/uploads/workspace1234/jD6Qzs6lSHy2bHAwFfCrjqU9RL3vCxFgYVl2nQrUYA.png?se=2057-04-01T19%3A27%3A52Z&sp=c&sv=2018-03-28&sr=b&sig=Jh...qYQ%3D' \ --header 'x-ms-blob-type: BlockBlob' \ --data-binary '@/Users/testuser/jD6Qzs6lSHy2bHAwFfCrjqU9RL3vCxFgYVl2nQrUYA.png' ``` ### Response #### Success Response (201) Typically returns a 201 Created status upon successful upload. #### Error Response (403) - **Error**: 'This request is not authorized to perform blob overwrites.' - This error occurs if attempting to upload to the same URL multiple times. ``` -------------------------------- ### Create File Widget on Mural using cURL Source: https://developers.mural.co/public/docs/how-to-upload-a-file-to-a-mural This code snippet shows how to create a file widget on a Mural board using the uploaded file. It requires your mural ID, an authentication token, and the file name generated in the asset creation step. You can specify dimensions and position for the widget. ```shell curl --request POST 'https://app.mural.co/api/public/v1/murals//widgets/file' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data-raw '{ \ "name": "", \ "x":350, \ "y":370, \ "width": 600, \ "height": 600, \ "presentationIndex": 0, \ "rotation": 0 \ }' ``` -------------------------------- ### Create Asset URL API Source: https://developers.mural.co/public/docs/how-to-upload-a-file-to-a-mural This endpoint is used to create an asset URL which is necessary for uploading a file to Mural storage. ```APIDOC ## POST /api/public/v1/murals/{muralId}/assets ### Description Creates an asset URL to prepare for file uploads to Mural storage. ### Method POST ### Endpoint /api/public/v1/murals/{muralId}/assets ### Parameters #### Path Parameters - **muralId** (string) - Required - The ID of the mural where the asset will be created. #### Request Body - **fileExtension** (string) - Required - The extension of the file to be uploaded (e.g., "pdf"). ### Request Example ```json { "fileExtension": "pdf" } ``` ### Response #### Success Response (200) - **value.url** (string) - The URL in the storage where the file will be uploaded. - **value.name** (string) - The path of the workspace followed by the file name. - **value.headers** (object) - The headers required for uploading to the storage. #### Response Example ```json { "value": { "url": "https://url:443/uploads/workspace1234/jD6Qzs6lSHy2bHAwFfCrjqU9RL3vCxFgYVl2nQrUYA.pdf?se=2057-04-01T19%3A27%3A52Z&sp=c&sv=2018-03-28&sr=b&sig=Jh...qYQ%3D", "name": "workspace1234/jD6Qzs6lSHy2bHAwFfCrjqU9RL3vCxFgYVl2nQrUYA.pdf", "headers": { "x-ms-blob-type": "BlockBlob" } } } ``` #### Error Response ```json { "code": "ASSET_TYPE_FORBIDDEN", "message": "The asset's file extension is invalid." } ``` ``` -------------------------------- ### HTTP Request to Retrieve Next Page of Data Source: https://developers.mural.co/public/docs/pagination This HTTP request demonstrates how to fetch the next page of results from a paginated API. It involves appending the 'next' token, obtained from the previous response's 'next' field, as a query parameter to the API endpoint. ```http GET /api/public/v1/workspaces?next= ``` -------------------------------- ### Create Image Widget on Mural (cURL) Source: https://developers.mural.co/public/docs/how-to-upload-an-image-to-a-mural This snippet illustrates how to create an image widget on a mural after the image has been successfully uploaded to storage. It requires the mural ID, an authorization token, and the 'name' field (asset path) received during the asset URL creation. You can specify properties like position, size, and border. ```shell curl --request POST 'https://app.mural.co/api/public/v1/murals//widgets/image' \ --header 'Authorization: Bearer ' \ --header 'Content-Type: application/json' \ --data-raw '{ "name": "", "x":350, "y":370, "width": 600, "height": 600, "border": true, "presentationIndex": 0, "rotation": 0, "showCaption": false }' ``` -------------------------------- ### HTTP Request to Limit Results Per Page Source: https://developers.mural.co/public/docs/pagination This HTTP request shows how to control the number of items returned in a paginated API response using the 'limit' query parameter. Setting a specific limit allows for more granular control over data retrieval. ```http GET /api/public/v1/workspaces?limit=10 ``` -------------------------------- ### Request Refresh Token using cURL in Postman Source: https://developers.mural.co/public/docs/testing-with-postman This cURL command is used to import into Postman to initiate the refresh token flow. It requires basic authentication (client ID and secret) and the current refresh token to obtain a new access token and refresh token. The `Authorization` header must be a base64 encoded string of '{client_id}:{client_secret}'. ```sh curl --location --request POST 'https://app.mural.co/api/public/v1/authorization/oauth2/refresh' \ --header 'Authorization: Basic username and password' \ --header 'Content-Type: application/json' \ --data-raw '{ "grant_type":"refresh_token", "refresh_token": "refresh_token_value" }' ``` -------------------------------- ### Mural API Error Response Format Source: https://developers.mural.co/public/docs/error-codes Describes the standard JSON format for error responses from the Mural API. ```APIDOC ## Error Response Format When the Mural API server responds with an error, the response body will follow this structure: ### Response Body ```json { "code": "", "message": "" } ``` - **code** (string) - An identifier for the specific error. - **message** (string) - A human-readable description of the error. ``` -------------------------------- ### User Authentication: Access Token Request Source: https://developers.mural.co/public/docs/oauth Exchange the authorization code obtained from the authorization request for an access token using a POST request to the token endpoint. ```APIDOC ## Authenticate users: Access Token Request Exchange the authorization code for an access token. ### Method POST ### Endpoint `https://app.mural.co/api/public/v1/authorization/oauth2/token` ### Parameters #### Request Body - **client_id** (string) - Required - The client identifier for your app. - **client_secret** (string) - Required - The secret key for your app. - **redirect_uri** (string) - Required - The same redirect URI used in the authorization request. - **code** (string) - Required - The authorization code received from the authorization server. - **grant_type** (string) - Required - Must be `authorization_code`. ### Request Example ```sh curl -X POST \ 'https://app.mural.co/api/public/v1/authorization/oauth2/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'client_id=my_client_id' \ --data-urlencode 'client_secret=my_client_secret' \ --data-urlencode 'redirect_uri=my_callback' \ --data-urlencode 'code=my_code' \ --data-urlencode 'grant_type=authorization_code' ``` ### Response #### Success Response (200) Returns a JSON object containing the access token and its expiration time. ```json { "access_token": "", "expires_in": , "refresh_token": "" } ``` #### Response Fields - **access_token** (string) - The obtained access token. - **expires_in** (integer) - The duration in seconds until the access token expires. - **refresh_token** (string) - The refresh token to obtain a new access token when the current one expires. ```