# Freshdesk

- Tool: Bubble
- Difficulty: Beginner
- Time required: 1–2 hours
- Last updated: July 2026

## TL;DR

Connect Bubble to Freshdesk using the API Connector with Basic Auth — your Freshdesk API key in the username field and the literal character X as the password, base64-encoded together. Build a white-labeled customer support portal where users submit, view, and track their own tickets entirely inside Bubble, bypassing Freshdesk's native portal customization limits.

## Building a white-labeled Freshdesk support portal in Bubble

Freshdesk's API authentication has the most distinctive quirk in the support tool category: instead of a standard Authorization header with a key, Freshdesk uses HTTP Basic Auth where the **API key is the username** and the **literal character X is the password**. Freshdesk's own documentation describes this as 'using X as a fake password.' The combination `api_key:X` is base64-encoded and placed in the Authorization header.

In Bubble, there is no native Basic Auth toggle in the API Connector, so you pre-encode the credentials once using any base64 encoder and paste the resulting string directly into a custom Authorization header marked Private.

The primary Bubble use case for Freshdesk is a custom customer-facing support portal. Freshdesk's native portal customization has limited branding controls — you cannot fully match your brand identity. With Bubble, you build a fully branded portal where customers log in (via Bubble's own auth), see only their own tickets, submit new requests, and track status updates. The Freshdesk API handles all the ticketing logic behind the scenes.

For inbound events (ticket created in Freshdesk → trigger Bubble automation), Freshdesk can send webhook POST requests to a Bubble Backend Workflow endpoint. This requires a Bubble paid plan. Rate limits on Freshdesk's free and Growth plans (40 req/min) are low — a Bubble page polling for ticket updates every 10 seconds for 5 simultaneous users will exceed this immediately. Use the inbound webhook path for real-time updates rather than polling.

## Before you start

- A Freshdesk account — the API is available on all paid plans (Growth, Pro, Enterprise) and the free 3-agent plan. Get your API key from Profile Settings → API Key
- The API Connector plugin installed in your Bubble app (Plugins tab → Add plugins → search 'API Connector' by Bubble → Install)
- A base64 encoder (your browser's developer console, any online encoder, or the Node.js Buffer.from('apikey:X').toString('base64') command) to pre-encode your credentials
- For inbound Freshdesk webhooks: a Bubble paid plan (Starter or above) — Backend Workflows are not available on the Free plan

## Step-by-step guide

### 1. Get your Freshdesk API key and encode your credentials

Log in to your Freshdesk account at yourcompany.freshdesk.com. Click on your profile picture in the top-right corner and select 'Profile Settings.' Scroll down to find the 'Your API Key' section — it displays an alphanumeric string like `abc123xyz456def789`. Copy this key.

Now you need to base64-encode the combination of your API key and the literal letter X, separated by a colon: `your_api_key:X`.

The letter X is uppercase and is exactly one character — it is Freshdesk's documented authentication pattern for API token usage (as opposed to password-based auth). Encoding with just the key and no password is not supported — you must include the `:X` suffix.

To encode:
- In your browser's developer console (F12 → Console), type: `btoa('your_api_key:X')` and press Enter — this gives the base64 string.
- Alternatively, use any online base64 encoder: encode the string `your_api_key:X`.

The result is a base64 string that looks something like `YWJjMTIzeHl6NDU2ZGVmNzg5Olg=`. This is the value you will paste into Bubble.

Keep both the original API key and the base64-encoded string — you will need the base64 version for the Bubble API Connector.

```
// Base64 encoding your Freshdesk credentials:
// Your API key example: YourApiKey123
// Combined string: YourApiKey123:X   (note the colon and uppercase X)
// Base64 result: encode('YourApiKey123:X')

// Browser console method:
btoa('YourApiKey123:X')
// Result: 'WW91ckFwaUtleTEyMzpY'

// The Authorization header value will be:
// Basic WW91ckFwaUtleTEyMzpY

// Your Freshdesk base URL:
https://yourcompany.freshdesk.com/api/v2
// Replace 'yourcompany' with your actual Freshdesk subdomain
```

**Expected result:** You have your Freshdesk API key from Profile Settings and a base64-encoded string of `api_key:X` ready to paste into Bubble.

### 2. Configure the Bubble API Connector with the Freshdesk Authorization header

In your Bubble editor, go to Plugins in the left sidebar. Click 'Add another API' and name it 'Freshdesk.' Under the API group settings, set the base URL to `https://yourcompany.freshdesk.com/api/v2` — replace `yourcompany` with your actual Freshdesk subdomain (visible in your browser URL when logged in to Freshdesk).

Add a shared header at the API group level:
- Header name: `Authorization`
- Header value: `Basic ` followed by your base64-encoded string from the previous step
  Example: `Basic WW91ckFwaUtleTEyMzpY`
- Check the **Private** checkbox next to this header

Also add a shared header:
- Header name: `Content-Type`
- Header value: `application/json`

Now add your first call. Click 'Add another call' and name it 'Get Tickets.' Set the method to GET and the URL to `/tickets` (relative to the base URL). Add URL parameters:
- `filter`: text, with a default value of `open` (options: open, pending, resolved, all_tickets)
- `page`: number, default 1
- `per_page`: number, default 30

Click 'Initialize call.' Leave the filter as 'open' and click 'Send.' Freshdesk returns an array of ticket objects — Bubble will detect the response array. Note that the response is a direct array (not wrapped in a key), so set 'Use as' to 'Data' and the list type to 'array of items.'

If Initialize call returns 'There was an issue setting up your call,' double-check your base64 encoding. A common error is missing the space after `Basic ` in the header value, or encoding `api_key:x` with lowercase x instead of uppercase X.

```
// API Connector: Freshdesk → Get Tickets
// Method: GET
// Base URL: https://yourcompany.freshdesk.com/api/v2
// Call URL: /tickets
//
// Shared headers (at API group level):
// Authorization: Basic <base64(api_key:X)>  // mark Private
// Content-Type: application/json
//
// URL parameters:
// filter: open          (or pending, resolved, all_tickets)
// page: 1               (pagination)
// per_page: 30          (max 100 per Freshdesk docs)
//
// Example response (array, not wrapped in a key):
// [
//   {
//     "id": 12345,
//     "subject": "My order hasn't arrived",
//     "status": 2,
//     "priority": 1,
//     "requester_id": 6789,
//     "created_at": "2026-07-10T09:00:00Z",
//     "updated_at": "2026-07-10T11:30:00Z",
//     "tags": ["billing", "urgent"]
//   }
// ]
```

**Expected result:** The Freshdesk API Connector group is configured with the Private Authorization header. The Get Tickets call initializes successfully and Bubble detects the array of ticket objects.

### 3. Create tickets from a Bubble form with POST /tickets

The ticket creation endpoint is the most important write call for a customer portal — customers submit new support requests through a Bubble form and the ticket appears in Freshdesk automatically.

Add a new call under the Freshdesk API group: name it 'Create Ticket,' method POST, URL `/tickets`. The JSON body must include these fields:

- `subject`: text (required) — the ticket title
- `description_html`: text (required) — the ticket body **as HTML**. Note: `description` (plain text) is deprecated in v2; always use `description_html`. Even if your content is plain text, wrap it in `<p>your text</p>` tags.
- `email`: text (required) — the requester's email address
- `priority`: number (required) — 1=Low, 2=Medium, 3=High, 4=Urgent
- `status`: number (required) — 2=Open is the correct starting state for new tickets

Optional fields:
- `tags`: list of text strings for categorization
- `type`: text — custom ticket type defined in your Freshdesk settings

In your Bubble form page, add Text Input fields for Subject and Description, and a Dropdown for Priority. Wire the Submit button to a Backend Workflow that calls Create Ticket, passing the form values as dynamic parameters. Store the returned `id` in the User record or a Custom State so the UI can immediately show the new ticket without a full page refresh.

To show the new ticket to the customer right away, add a 'Refresh the page' or update a Custom State list to append the new ticket object to the existing displayed list.

```
// API Connector: Freshdesk → Create Ticket
// Method: POST
// URL: /tickets  (relative to base URL)
// Authorization: Basic <base64(api_key:X)>  // shared Private header
// Content-Type: application/json
//
// JSON body:
{
  "subject": "<dynamic_ticket_subject>",
  "description_html": "<p><dynamic_ticket_description></p>",
  "email": "<dynamic_requester_email>",
  "priority": 2,
  "status": 2
}

// Note: 'description' (plain text) is deprecated in v2.
// Always use 'description_html' — even for plain text wrap in <p> tags.

// Priority codes: 1=Low, 2=Medium, 3=High, 4=Urgent
// Status codes: 2=Open, 3=Pending, 4=Resolved, 5=Closed

// Successful response includes:
// {
//   "id": 67890,
//   "subject": "...",
//   "status": 2,
//   "created_at": "2026-07-10T12:00:00Z"
// }
```

**Expected result:** Submitting the Bubble form creates a real Freshdesk ticket. The response returns the new ticket ID. The ticket is visible in the Freshdesk agent dashboard under the Open filter.

### 4. Build a customer-facing ticket list with filtering and pagination

The core of your customer support portal is a list of the current customer's tickets. Freshdesk returns tickets by filter, so you need to filter by the requester's email to show only the logged-in user's own tickets.

Add a call 'Search Tickets' using GET `/search/tickets` with the query parameter:
- `query`: `"requester_id:6789"` — or use the email-based search: `"requester:[email]"` where `[email]` is the current user's email address surrounded by single quotes.

Example URL: `/search/tickets?query="requester:'customer@example.com'"`

This returns a search results object with `results` (array of tickets) and `total` (count). In Bubble, initialize this call with a real email that has existing tickets to get Bubble to detect the `results` array correctly.

Bind a Repeating Group to this call's `results` array. Inside each row, display:
- Subject (text element)
- Status badge: use a Conditional on a Group's background color — green for Resolved, yellow for Pending, red for Open
- Priority badge: similar conditional coloring
- Created date formatted as 'MMM D, YYYY'
- A 'View Details' button that navigates to a detail page, passing the ticket ID as a URL parameter

For pagination, Freshdesk's search endpoint does not use page/per_page params — it returns up to 30 results per request by default. For the filter-based GET /tickets endpoint, use `page` and `per_page` params and add 'Previous' and 'Next' buttons that increment/decrement a page number Custom State.

Because Freshdesk's free and Growth plans allow only 40 requests per minute, avoid automatic refresh timers. Instead, show a 'Refresh' button that lets the customer manually reload the ticket list.

```
// API Connector: Freshdesk → Search Customer Tickets
// Method: GET
// URL: /search/tickets
// Query parameter:
// query: "requester:'customer@example.com'"
//   (single quotes around email are required by Freshdesk search syntax)
//
// Example constructed URL:
// https://yourcompany.freshdesk.com/api/v2/search/tickets
//   ?query="requester:'jane@example.com'"
//
// Response:
// {
//   "results": [
//     { "id": 123, "subject": "...", "status": 2, ... }
//   ],
//   "total": 5
// }

// For paginated list (GET /tickets with filter):
// URL: /tickets
// Parameters:
// email: <current_user's_email>   // filter by requester email
// page: <page_state>              // Custom State integer, starts at 1
// per_page: 20
```

**Expected result:** The customer portal shows a Repeating Group of tickets belonging to the logged-in user. Status badges are color-coded. The customer can filter by status and load more tickets via pagination controls.

### 5. Set up inbound Freshdesk webhook events via Bubble Backend Workflow

To receive real-time events from Freshdesk (ticket created, ticket updated, status changed), you expose a Backend Workflow endpoint in Bubble and register it as a webhook target in Freshdesk's Automation rules.

This requires a **Bubble paid plan** — Backend Workflows are not available on the Free plan.

In Bubble, go to Settings → API and check 'This app exposes a Workflow API.' Your API base URL will be: `https://yourappname.bubbleapps.io/api/1.1/wf/`

Open the Backend Workflows section and click 'Add workflow.' Name it `freshdesk_webhook`. In the workflow, click 'Detect data' — Bubble will listen for the next incoming POST request and auto-detect the schema.

Meanwhile, in Freshdesk Admin Settings → Automations → Ticket Automations, create a new automation rule. Set the trigger (e.g., 'When a ticket is created' or 'When status changes to Resolved'). Under 'Perform these actions,' choose 'Trigger Webhook.' Enter your Bubble Backend Workflow URL: `https://yourappname.bubbleapps.io/api/1.1/wf/freshdesk_webhook`.

Set the webhook method to POST, Content-Type to JSON, and add the ticket fields you want to receive in the body: `ticket_id`, `status`, `subject`, `requester_email`, `priority`.

Send a test event from Freshdesk (create a test ticket or trigger the automation manually). Bubble's 'Detect data' captures the incoming JSON and auto-detects the schema fields. After detection, add workflow actions to process the event — for example, updating a Bubble 'Support_Ticket' data type record, sending a Slack notification, or updating the user's ticket count.

Add a 'Return data from API' action that responds with `{"status": "ok"}` to acknowledge receipt. Freshdesk expects a 200 response within a few seconds.

```
// Bubble Backend Workflow endpoint URL:
https://yourappname.bubbleapps.io/api/1.1/wf/freshdesk_webhook

// Freshdesk webhook payload (example for ticket created event):
// POST to your Backend Workflow URL
// Content-Type: application/json
// Body:
{
  "ticket_id": 12345,
  "subject": "My order hasn't arrived",
  "status": 2,
  "priority": 2,
  "requester_email": "customer@example.com",
  "created_at": "2026-07-10T09:00:00Z"
}

// Backend Workflow response (to acknowledge receipt):
{ "status": "ok" }

// Freshdesk Automation setup path:
// Admin Settings → Automations → Ticket Automations
// → New Rule → Trigger: On ticket creation
// → Action: Trigger Webhook → POST to Bubble URL
```

**Expected result:** Freshdesk sends a webhook POST to your Bubble Backend Workflow URL when the automation rule triggers. Bubble detects the ticket fields and processes them in the workflow. Bubble Logs tab → Workflow logs shows the incoming request and the 200 acknowledgment response.

### 6. Test, secure, and monitor your Freshdesk integration

Before going live, run through this validation checklist:

**1. Privacy check:** Open your deployed Bubble app in a browser, open DevTools (F12 → Network tab), and trigger a ticket-loading workflow. Filter network requests by `freshdesk.com`. You should see NO requests going directly to Freshdesk from the browser — all calls should go through Bubble's server. If you see direct browser requests, your API calls are not running server-side. Move them to Backend Workflows and ensure the Private checkbox is set on the Authorization header.

**2. Rate limit awareness:** Freshdesk's free and Growth plans allow 40 requests per minute. If multiple users load your portal simultaneously and each triggers a ticket-list API call, you can easily hit this limit. Implement 'lazy loading' — only load tickets when a user explicitly clicks 'Load Tickets' rather than automatically on page load. Pro and Enterprise plans allow 100 req/min.

**3. Privacy rules for stored ticket data:** If you cache Freshdesk ticket data in Bubble's database (a common pattern to reduce API calls), add Data tab → Privacy rules to the Ticket data type. Ensure customers can only read their own tickets by setting a rule: 'This thing is visible to Current User when Email = requester_email.'

**4. Error handling:** Add workflow error handlers for 401 (check API key encoding), 403 (check account plan limits), 404 (ticket not found — it may have been deleted in Freshdesk), and 429 (rate limit exceeded — add a delay and retry). Display user-friendly messages rather than raw HTTP status codes.

**5. Test the complete create-to-display flow:** Create a ticket through your Bubble form, verify it appears in Freshdesk's agent dashboard, then refresh your Bubble portal list to confirm the ticket appears for the customer.

```
// Freshdesk API error codes:
// 401 Unauthorized — check base64 encoding; ensure 'X' is uppercase
// 403 Forbidden — check account plan; some endpoints require higher plans
// 404 Not Found — ticket was deleted in Freshdesk or wrong ID
// 429 Too Many Requests — rate limit exceeded (40 req/min on free/Growth)
//
// Privacy rule pattern for Bubble (Data tab → Ticket type → Privacy):
// Rule: 'This Thing is visible to user when
//   Ticket's requester_email = Current User's email'
//
// WU economy tip:
// Each Freshdesk API call from Bubble consumes Bubble Workload Units.
// Cache ticket list results in Custom States and refresh only on
// explicit user action — not automatically on every page render.
```

**Expected result:** Your Freshdesk integration is secure (no credentials in browser network tab), handles rate limits gracefully, applies privacy rules to stored ticket data, and shows appropriate error messages to users when Freshdesk calls fail.

## Best practices

- Always mark the Authorization header Private in Bubble's API Connector — the base64-encoded string gives full API access to your Freshdesk account and must never appear in browser DevTools.
- Use `description_html` (not the deprecated `description`) for all ticket creation and update calls in Freshdesk v2 — plain `description` is no longer supported and causes 400 errors.
- Cache the ticket list in a Custom State after the first load and show a manual 'Refresh' button rather than auto-refreshing — Freshdesk's 40 req/min limit on free and Growth plans is easily breached by automatic polling in multi-user apps.
- Add Bubble Privacy rules to any Freshdesk ticket data you store in Bubble's database — ensure customers can only read their own tickets by filtering on the requester email field.
- Use Freshdesk's inbound webhook path (Backend Workflow endpoint) for real-time ticket updates instead of polling — webhooks consume fewer API calls and provide instant notification, whereas polling on a timer multiplies API calls with every active user.
- Store the Freshdesk subdomain in a Bubble 'Option Set' or app-level config value rather than hardcoding it in the API Connector base URL — this makes it easier to switch accounts or support multi-tenant setups without re-configuring every API call.
- Handle Freshdesk's numeric status codes with a Bubble Option Set (Open=2, Pending=3, Resolved=4, Closed=5) to display friendly labels and conditional colors rather than raw numbers in your UI.

## Use cases

### White-labeled customer support ticket portal

Build a Bubble portal where your customers log in with their own accounts, see only their support tickets, submit new requests, and check status updates — all styled to match your brand. Freshdesk handles the ticketing, SLA, and agent workflow behind the scenes while your customers interact only with the Bubble UI.

Prompt example:

```
On the Support page, load tickets filtered by the logged-in user's email: GET /tickets with filter=open and requester_id matching the current user's Freshdesk contact ID. Display results in a Repeating Group with ticket subject, status badge, and created date. Add a New Ticket button that opens a form calling POST /tickets on submit.
```

### Internal ticket triage dashboard for support managers

Create a Bubble dashboard for support managers to view all open and pending tickets, assign them to agents, and update priorities — without agents needing individual Freshdesk logins. This works well for teams using Bubble as their primary operations hub and wanting support visibility in the same interface.

Prompt example:

```
Load all open tickets via GET /tickets?filter=open with pagination. Display in a Bubble table with columns for subject, requester name, priority (color-coded), and assignee. Add a Dropdown to each row to change priority via PATCH /tickets/{id} with the new priority value.
```

### Automated ticket creation from Bubble form submissions

Trigger Freshdesk ticket creation automatically when a Bubble form is submitted — a contact form, a refund request, or a bug report. The Backend Workflow creates the ticket in Freshdesk with the appropriate tags and priority, and emails a confirmation to the customer. No agent intervention required for intake.

Prompt example:

```
When a Bug Report form is submitted, trigger a Backend Workflow that POSTs to /tickets with subject from the form title field, description_html from the details field, email from the current user's email, priority=2 (medium), and status=2 (open). Store the returned ticket ID in the user's Bubble record for future status lookups.
```

## Troubleshooting

### All Freshdesk API calls return 401 Unauthorized

Cause: The base64-encoded Authorization header is incorrect. The most common mistakes are: encoding `api_key:x` with lowercase x instead of uppercase X, missing the colon between the key and X, missing the space after 'Basic ' in the header value, or the API key has been regenerated in Freshdesk and the header not updated.

Solution: Go to Freshdesk Profile Settings and copy your current API key. Re-encode `your_api_key:X` (uppercase X, colon separator) using `btoa('your_api_key:X')` in a browser console. Update the Authorization header in Bubble's API Connector to `Basic ` + the new base64 string (with a space between 'Basic' and the encoded string). Click Initialize call to verify the new header returns 200.

```
// Correct Authorization header format:
// Authorization: Basic WW91ckFwaUtleTEyMzpY
//
// Where 'WW91ckFwaUtleTEyMzpY' = btoa('YourApiKey123:X')
//
// Wrong formats:
// Authorization: Basic WW91ckFwaUtleTEyMzp4  // lowercase x
// Authorization: BasicWW91ckFwaUtleTEyMzpY   // missing space after Basic
// Authorization: WW91ckFwaUtleTEyMzpY         // missing 'Basic ' prefix
```

### POST /tickets returns 400 Bad Request when creating a ticket

Cause: The most common cause is using the deprecated `description` field instead of `description_html`, or passing an empty required field. Freshdesk v2 requires `description_html` even if the content is plain text. Missing `email` or `subject` also causes 400.

Solution: Check the JSON body of your Create Ticket call in Bubble's API Connector. Replace any `description` field with `description_html` and wrap the value in `<p>...</p>` HTML tags. Verify that `subject`, `email`, `priority`, and `status` are all populated with non-empty values. Use the Initialize call with real test values to confirm the call succeeds before wiring it to a form.

```
// Wrong (returns 400):
{ "description": "My order is missing" }

// Correct:
{ "description_html": "<p>My order is missing</p>" }
```

### Initialize call fails with 'There was an issue setting up your call'

Cause: Bubble cannot detect the response schema because the Initialize call returned a non-200 response. This happens when the API key is wrong (returns 401) or the base URL has the wrong subdomain (returns 404).

Solution: Verify your Freshdesk subdomain: the URL when logged in to Freshdesk is `https://yourcompany.freshdesk.com` — use `yourcompany` (not `yourcompany.freshdesk.com`) as the subdomain portion of your base URL. The full base URL should be `https://yourcompany.freshdesk.com/api/v2`. After fixing, re-run Initialize call — Bubble needs a valid 200 response to detect the response schema.

### Freshdesk ticket list shows all tickets, not just the current user's tickets

Cause: The GET /tickets endpoint without an email filter returns all tickets visible to the API key (typically all tickets in the account). To show only a specific customer's tickets, you must filter by requester email using the search endpoint or the `email` parameter.

Solution: Use GET /search/tickets with query parameter `query` set to `"requester:'user@example.com'"` — building the query string dynamically in Bubble: `"requester:'" + Current User's email + "'"`. Alternatively, use the GET /tickets endpoint with the `email` parameter set to the current user's email address to filter by requester.

```
// Correct: filter by requester email
// GET /search/tickets?query="requester:'user@example.com'"
// OR
// GET /tickets?email=user@example.com
```

### Backend Workflow for inbound Freshdesk webhooks is not receiving events

Cause: The Backend Workflow API is not enabled in Bubble Settings (Settings → API → 'This app exposes a Workflow API' unchecked), or the workflow URL in Freshdesk's automation includes `/initialize` at the end (the initialization URL variant used during setup — it must be removed for production).

Solution: Go to Bubble Settings → API and verify 'This app exposes a Workflow API' is checked. Check the webhook URL registered in Freshdesk — it should be `https://yourapp.bubbleapps.io/api/1.1/wf/freshdesk_webhook` without `/initialize`. Also confirm the Freshdesk automation rule is active (enabled) and the trigger conditions are met. Check Bubble Logs → Workflow logs for any incoming requests.

## Frequently asked questions

### Why is the password literally the letter X for Freshdesk API authentication?

Freshdesk uses standard HTTP Basic Auth, which requires both a username and password. When using an API key instead of a user's actual password, Freshdesk's documentation specifies using the API key as the username and any non-empty string — conventionally the letter X — as the placeholder password. The X has no special meaning; it just satisfies the Basic Auth format requirement. Freshdesk ignores the password value and authenticates solely based on the API key.

### Do I need a paid Freshdesk plan to use the API in Bubble?

Freshdesk's API is available on the free 3-agent Sprout plan and all paid plans. However, the free plan has lower rate limits (40 requests per minute) and limited webhook trigger options in Automation rules. For a production Bubble customer portal, a paid Freshdesk plan (Growth or above) is recommended for higher rate limits (100 req/min on Pro+) and more automation flexibility. Inbound webhooks to Bubble also require a Bubble paid plan for Backend Workflows.

### How do I let customers view only their own tickets in my Bubble portal?

Use the Freshdesk search endpoint — GET /search/tickets with the query parameter set to `"requester:'customer@example.com'"` (with the customer's email from Bubble's Current User object). This returns only tickets where that email is the requester. Do not use GET /tickets without filtering — it returns all tickets visible to your API key, which would expose other customers' data.

### Can I allow customers to add replies or comments to their Freshdesk tickets from Bubble?

Yes. Freshdesk's API supports adding conversation notes via POST /tickets/{id}/reply with a body containing `body_html` (the reply text as HTML) and the `user_id` of the replying agent, or `from_email` for customer replies. Add a Reply text area and Send button on your ticket detail page, wiring the submit action to a Backend Workflow that calls this endpoint.

### What should I do when the Freshdesk rate limit is exceeded?

Freshdesk returns HTTP 429 when the rate limit (40 req/min on free/Growth, 100 req/min on Pro+) is breached. In Bubble's workflow error handler, add a 'When API call returns error 429' condition that shows a user-friendly message like 'Loading is temporarily paused — please try again in a moment' instead of a raw error. Avoid automatic polling intervals; use manual 'Refresh' buttons to give users control over when API calls fire.

### How do I update a ticket's status from my Bubble portal — for example, mark it as Resolved?

Use PATCH /tickets/{id} with a body containing `{"status": 4}` (4=Resolved). Add a 'Mark Resolved' button in your ticket detail view that triggers a Backend Workflow calling this PATCH action. After the call succeeds, update the status displayed in your Bubble UI using a Custom State change so the customer sees the updated status immediately without reloading the full ticket list.

---

Source: https://www.rapidevelopers.com/bubble-integrations/freshdesk
© RapidDev — https://www.rapidevelopers.com/bubble-integrations/freshdesk
