Skip to main content
RapidDev - Software Development Agency
bubble-integrationsBubble API Connector

Sinch

Connect Bubble to Sinch using two API Connector calls: one to fetch a short-lived OAuth 2.0 Bearer token from Sinch's auth server, and one to send messages via the Conversation API. By chaining these calls inside a Backend Workflow, your Sinch Key Secret stays Private on Bubble's servers — never reaching the browser — while you gain the ability to send SMS, WhatsApp, and RCS from a single endpoint.

What you'll learn

  • How to set up two chained API Connector calls for Sinch's OAuth 2.0 token flow
  • How to keep your Sinch Key Secret Private using Bubble's server-side headers
  • How to build a Backend Workflow that fetches a token then sends a message
  • How to configure channel_priority for SMS/WhatsApp/RCS fallback delivery
  • How to handle token expiry by storing and checking expiry timestamps in Bubble's database
  • How to read Sinch Dashboard delivery logs to debug message failures
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate19 min read90 minutesCommunicationLast updated July 2026RapidDev Engineering Team
TL;DR

Connect Bubble to Sinch using two API Connector calls: one to fetch a short-lived OAuth 2.0 Bearer token from Sinch's auth server, and one to send messages via the Conversation API. By chaining these calls inside a Backend Workflow, your Sinch Key Secret stays Private on Bubble's servers — never reaching the browser — while you gain the ability to send SMS, WhatsApp, and RCS from a single endpoint.

Quick facts about this guide
FactValue
ToolSinch
CategoryCommunication
MethodBubble API Connector
DifficultyIntermediate
Time required90 minutes
Last updatedJuly 2026

One API, Four Channels — With a Token-Refresh Twist

Sinch's Conversation API is powerful because a single POST request can attempt delivery over SMS, WhatsApp, RCS, and MMS in the order you specify. If the first channel fails, Sinch automatically tries the next one. For Bubble builders, this means you can build a notification system that reliably reaches users on whatever messaging app they prefer — without managing separate integrations for each channel.

The catch is authentication. Sinch does not use a static API key for the Conversation API. Instead, you exchange a Key ID and Key Secret for a Bearer token that lasts roughly one hour. Your Bubble integration must handle this lifecycle: fetch a token, cache it, use it for up to an hour, then refresh it before it expires. Bubble's Backend Workflows are the right tool here — they run server-side, respect the 'Private' flag on your Key Secret, and can be scheduled to run on a timer.

Before any of this works, you also need to create a Conversation App inside your Sinch Dashboard and attach at least one channel (SMS or WhatsApp) to it. The app_id from that Conversation App is required in every messages:send request.

This integration requires Bubble's Starter plan ($32/month) or higher because Backend Workflows (API Workflows) are not available on the Free plan. If you are on the Free plan, you cannot keep the Key Secret server-side, which means you should not proceed — exposing your Key Secret client-side would allow anyone to send messages from your Sinch account.

Integration method

Bubble API Connector

Two chained API Connector calls: token fetch from auth.sinch.com, then message send via the Conversation API — both routed through a Backend Workflow to keep credentials Private.

Prerequisites

  • A Sinch account with a project created at portal.sinch.com
  • A Sinch Conversation App with at least one channel (SMS or WhatsApp) configured in the Sinch Dashboard
  • Your Sinch Key ID and Key Secret from Dashboard → Access Keys
  • A Bubble app on the Starter plan ($32/month) or higher — Backend Workflows are required and not available on the Free plan
  • The API Connector plugin by Bubble installed in your app (Plugins tab → Add plugins → search 'API Connector')
  • A phone number or WhatsApp-registered number to use as the sender in your Conversation App

Step-by-step guide

1

Set Up Your Sinch Project and Conversation App

Log in to the Sinch Customer Dashboard at portal.sinch.com. Navigate to your project (or create a new one) and click 'Access Keys' in the left sidebar. Click 'New Key', give it a descriptive name like 'Bubble Integration', and copy both the Key ID and the Key Secret — the Key Secret is shown only once, so save it somewhere secure before closing the modal. Next, navigate to the 'Conversation' section in the left sidebar and click 'Apps'. Click 'Create new app', give it a name, and select your project region — choose US if your users are in the Americas, or EU if they are in Europe, because the base URL you use in your API Connector must match the region you select here. After creating the app, add at least one channel: click 'Add channel', select SMS, and follow the prompts to link a Sinch phone number. If you have a WhatsApp Business account connected to Sinch, you can add that channel too. Once the Conversation App is created, copy the App ID displayed on the app detail page. You will need this ID in the request body of every messages:send call. Your project ID is visible in the URL when viewing your project in the dashboard — also copy this, as it appears in the Conversation API endpoint path. Note your region's base URL: US is https://us.conversation.api.sinch.com/v1 and EU is https://eu.conversation.api.sinch.com/v1. Using the wrong region's URL with a valid project ID returns a 404 error that can be confusing to debug — make sure you use the URL that matches the region you selected when creating your Conversation App.

Pro tip: The Key Secret is shown only once in the Sinch Dashboard. If you close the modal without copying it, you will need to generate a new key. Create the key, immediately paste the secret into a secure password manager, and only then proceed to the next step.

Expected result: You have a Sinch Project ID, Key ID, Key Secret, Conversation App ID, and a confirmed region base URL. Your Conversation App has at least one channel active.

2

Add the Token Fetch Call in Bubble's API Connector

Open your Bubble app editor and click the 'Plugins' tab in the left sidebar. If you do not already have the API Connector installed, click 'Add plugins', search for 'API Connector', and install the one by Bubble. Once installed, click 'API Connector' to open its configuration panel. Click 'Add another API' and name this group 'Sinch Auth'. Do NOT add any shared headers to this group — the Sinch token endpoint uses Basic authentication with your Key ID and Key Secret, not a Bearer token. Instead, at the call level, set the authentication to 'Basic auth' and enter your Key ID as the Username and your Key Secret as the Password. Click the 'Private' checkbox next to the Password field so the Key Secret is marked private and will never be sent to the browser. Add a new call within this group. Name it 'Get Access Token'. Set the method to POST and the URL to https://auth.sinch.com/oauth2/token. Under the request body, add a parameter with key 'grant_type' and value 'client_credentials' and mark the type as 'text' (not 'dynamic'). Set 'Use as' to 'Action'. Click 'Initialize call'. This sends an actual request to Sinch's auth server using your credentials and parses the response shape so Bubble knows the structure. You should receive a JSON response containing an 'access_token' field and an 'expires_in' field (typically 3600). Once Bubble shows the detected fields, click 'Save'. If the initialization fails with a 401, double-check that your Key ID is entered as the Username and Key Secret as the Password — not vice versa, which is a common mistake.

sinch-auth-call.json
1{
2 "method": "POST",
3 "url": "https://auth.sinch.com/oauth2/token",
4 "authentication": "Basic auth",
5 "username": "<Your Key ID>",
6 "password": "<Your Key Secret — mark PRIVATE>",
7 "body": {
8 "grant_type": "client_credentials"
9 }
10}

Pro tip: After the Initialize call succeeds, expand the detected fields and confirm you see 'access_token', 'token_type', and 'expires_in'. If you only see a partial response, Bubble may have timed out — click Initialize again. The response is small so this should complete in under 2 seconds.

Expected result: The API Connector shows a 'Get Access Token' call under the 'Sinch Auth' group with detected response fields including 'access_token' and 'expires_in'. The Key Secret is marked Private.

3

Add the Messages:Send Call for the Conversation API

Back in the API Connector panel, click 'Add another API' to create a second group — or you can add a second call under a new 'Sinch Messages' group for organization. Name the group 'Sinch Messages'. Add a shared header: key 'Authorization', value 'Bearer [access_token]'. Mark this header as 'Private' by checking the Private checkbox, and set the type to 'Dynamic' so you can pass in the actual token value at runtime from your workflow. Add a new call named 'Send Message'. Set the method to POST and the URL to: https://us.conversation.api.sinch.com/v1/projects/[project_id]/messages:send Replace 'us' with 'eu' if your Conversation App is in the EU region. Mark [project_id] as a dynamic parameter. In the JSON body, add the message structure. Set the body to the JSON shown in the code block below. Mark each field that will be set at runtime as 'Dynamic'. Set 'Use as' to 'Action'. To initialize this call, you need a real access token. Go to your Sinch auth call first, run it manually (you can use a test tool like Postman or open the Initialize call again), copy the access_token value, and paste it temporarily into the Authorization header value for initialization. Also fill in your real project_id, app_id, and a real phone number for recipient. Click 'Initialize call' — this should return a 200 OK with a message_id. Once detected, save the call and remove the hardcoded token value, leaving it as a Dynamic parameter.

sinch-send-message-call.json
1{
2 "method": "POST",
3 "url": "https://us.conversation.api.sinch.com/v1/projects/[project_id]/messages:send",
4 "headers": {
5 "Authorization": "Bearer [access_token -- PRIVATE, DYNAMIC]",
6 "Content-Type": "application/json"
7 },
8 "body": {
9 "app_id": "[app_id]",
10 "recipient": {
11 "identified_by": {
12 "channel_identities": [
13 {
14 "channel": "SMS",
15 "identity": "[phone_e164]"
16 }
17 ]
18 }
19 },
20 "message": {
21 "text_message": {
22 "text": "[message_text]"
23 }
24 },
25 "channel_priority_order": ["WHATSAPP", "SMS"]
26 }
27}

Pro tip: Always include 'SMS' as the last item in channel_priority_order. RCS messages only work on Android devices in supported regions. If you set channel_priority to only ['RCS'] and the recipient's device does not support it, the message will fail silently with no delivery — SMS as a fallback prevents this.

Expected result: The 'Send Message' call appears in the 'Sinch Messages' group with dynamic parameters for access_token (Private), project_id, app_id, phone number, and message text. Initialize call returned 200 with a message_id.

4

Build the Backend Workflow to Chain Token Fetch and Message Send

The Backend Workflow is the critical piece that keeps your Key Secret safe. Open the Bubble editor, navigate to the 'Backend Workflows' section (look for 'Backend Workflows' in the left panel — if you do not see it, go to Settings → API and enable 'This app exposes a Workflow API'). Click 'New API workflow' and name it 'sinch-send-message'. Add the following parameters to this Backend Workflow so it can receive the phone number and message text from your frontend: 'recipient_phone' (text), 'message_text' (text). You may also want to add 'app_id' as a parameter if you have multiple Conversation Apps. Before building the workflow steps, first go to your Data tab and create a new data type called 'Sinch Token' with two fields: 'access_token' (text) and 'expires_at' (date). This is where you will cache the token to avoid fetching a new one on every message send. Back in the Backend Workflow editor, add the first action: check if a valid cached token exists. Use 'Search for Sinch Tokens' and filter where expires_at is greater than 'Current date/time'. If a token is found, use it directly in the next step. If no valid token is found, trigger the 'Get Access Token' API action (your Sinch Auth call). After the token call, add a 'Create a new Sinch Token' step: set access_token to the result's access_token field, and set expires_at to 'Current date/time + 50 minutes' (using a slightly shorter window than the actual 60-minute expiry as a safety buffer). Finally, add the 'Send Message' API action (your Sinch Messages call), passing in the access_token (from the cached or newly fetched token), the project_id (stored as a constant in your workflow or as an App setting), the app_id, the recipient phone number from the workflow parameter, and the message text. This entire chain runs server-side — your Key Secret never leaves Bubble's servers. Note: Backend Workflows require Bubble's Starter plan ($32/month) or higher. If you see a message that API Workflows are not enabled, you need to upgrade your plan.

Pro tip: RapidDev's team has built this exact token-chain pattern across dozens of Bubble apps with Sinch, Webex, and GoToWebinar — if the multi-step auth flow feels complex, a free scoping call at rapidevelopers.com/contact can save you several hours of debugging. The most common mistake is not storing the expires_at timestamp, which causes unnecessary token fetches on every message send.

Expected result: You have a Backend Workflow named 'sinch-send-message' that checks for a cached token, fetches a new one if needed, stores it with an expiry timestamp, and calls the Sinch Conversation API messages:send endpoint. The workflow runs entirely server-side.

5

Wire the Backend Workflow to a Frontend Trigger

Now that the Backend Workflow exists, you can trigger it from anywhere in your Bubble app. The most common pattern is a button click — for example, a 'Send notification' button on an admin dashboard or an automatic trigger on a data change event. To trigger from a button: select the button element, click the 'Start/Edit Workflow' icon in the Properties panel. Add an action and search for 'Schedule API Workflow'. You will see your 'sinch-send-message' workflow listed. Select it and pass in the required parameters: the recipient's phone number (from an input element or a database field on the current page) and the message text. For automatic triggers based on data changes, use a 'Schedule API Workflow' action inside a Workflow that fires when a record changes — for example, when an Order's status changes to 'Shipped', schedule the sinch-send-message workflow with the order's customer phone number and a message like 'Your order has shipped!'. If you want the message send to happen immediately (not scheduled), you can use 'Schedule API Workflow' with 'Schedule for: Current date/time', which runs it as soon as the workflow is triggered. The distinction between running 'Schedule API Workflow' (always async) and a direct API call action is that Backend Workflows are always async — the frontend does not wait for a response before continuing, which is usually the desired behavior for message sending.

Pro tip: Check Bubble's Logs tab after triggering a send. Click 'Workflow logs' and look for your sinch-send-message workflow run. Expand it to see each action's result. If the token fetch succeeded but the message send failed, the error details from Sinch's API will appear in the log — this is much easier than debugging with no logs.

Expected result: Clicking the trigger button (or firing the automatic event) schedules the sinch-send-message Backend Workflow. The Logs tab shows the workflow running successfully with both the token fetch and message send actions completing.

6

Verify Delivery in Sinch Dashboard

After triggering a test message send from Bubble, open your Sinch Customer Dashboard at portal.sinch.com and navigate to Conversation → Logs. Select your Conversation App from the dropdown and look for the message you just sent. The log shows the message ID, the channel it was delivered on, and the delivery status (DELIVERED, QUEUED, FAILED). If the status is FAILED, click on the log entry to see the failure reason. Common reasons include: incorrect phone number format (Sinch requires E.164 format: +12125551234 with the plus sign and country code), channel configuration errors (WhatsApp sender not approved), or an expired token that was not refreshed correctly. To verify your token caching is working correctly, trigger two message sends within a minute of each other and check your Sinch Token data type in Bubble's Data tab. You should see only one token record (or the same token being reused), not two new ones being created on each send. If you see a new token created on each send, check your expiry comparison logic in the Backend Workflow. Check that your phone number field is storing numbers in E.164 format. If users enter numbers in national format (e.g., (212) 555-1234), you need to clean and format them before passing to Sinch. A simple JavaScript action in the Toolbox plugin can strip non-numeric characters and prepend the country code, or you can use a Bubble expression to format the value.

Pro tip: Sinch trial accounts have a limited number of free test messages. If you are testing heavily, check your Sinch Dashboard usage to avoid unexpectedly running out of trial credits. Purchase a small credit balance ($10-20) early in development to avoid interruptions.

Expected result: Sinch Dashboard shows the test message with DELIVERED status on the correct channel. Your Bubble Sinch Token data type shows a cached token with a future expires_at date. The Logs tab in Bubble shows the workflow completed without errors.

Common use cases

Multi-Channel Transactional Notifications

Send order confirmations, appointment reminders, or payment receipts via WhatsApp first, falling back to SMS automatically if the user does not have WhatsApp. One Sinch Conversation API call with channel_priority handles the fallback logic entirely on Sinch's side — your Bubble workflow just triggers the send.

Bubble Prompt

When the Order status changes to 'Shipped', trigger a Backend Workflow that sends a Sinch Conversation API message to the customer's phone number with channel_priority ['WHATSAPP', 'SMS'] and the tracking link in the message body.

Copy this prompt to try it in Bubble

Two-Factor Authentication (2FA) via SMS

Generate a one-time code in Bubble, store it with a 10-minute expiry on the user's record, and dispatch it via Sinch SMS using the Conversation API. On the verification page, check the submitted code against the stored value and expiry timestamp before granting access.

Bubble Prompt

When a user clicks 'Send verification code', generate a random 6-digit number, save it to the User's otp_code and otp_expiry fields, then trigger the Sinch Backend Workflow to send the code to their phone via SMS channel only.

Copy this prompt to try it in Bubble

Support Ticket Escalation Alerts

When a high-priority support ticket has been open for more than two hours without a response, trigger a Sinch Conversation API send to the on-call agent's phone number. Use RCS as the first channel priority to send a rich message with ticket details, falling back to SMS for devices that do not support RCS.

Bubble Prompt

Schedule a recurring Backend Workflow every 15 minutes that queries open tickets older than 2 hours with no agent_reply, then calls the Sinch send endpoint with channel_priority ['RCS', 'SMS'] for each ticket's assigned agent phone number.

Copy this prompt to try it in Bubble

Troubleshooting

Token fetch returns 401 Unauthorized

Cause: The Key ID or Key Secret is entered incorrectly, or you are using a legacy SMS API token (Service Plan ID + API Token) with the Conversation API auth endpoint.

Solution: In your Sinch Auth API Connector call, verify the Username field contains exactly your Key ID (starts with a UUID-like string) and the Password field contains your Key Secret. These credentials are for the Conversation API only — if you are trying to use the legacy SMS API (api.sinch.com/xms), it uses a different auth scheme with a Service Plan ID and API Token as Basic auth against a different endpoint. The two APIs are completely separate; do not mix credentials.

messages:send returns 404 Not Found even with valid credentials

Cause: The region in your base URL does not match the region your Sinch Conversation App was created in.

Solution: Check your Sinch Conversation App in the dashboard. The app detail page shows whether it was created in the US or EU region. If it is EU, your base URL must be https://eu.conversation.api.sinch.com/v1 — using https://us.conversation.api.sinch.com/v1 with an EU app returns 404 on the project ID even when the credentials are valid. Update the URL in your API Connector's Send Message call.

Initialize call on the Send Message call fails with 'There was an issue setting up your call'

Cause: The Initialize call was run with an expired or placeholder access token value, or without a real phone number in the recipient field.

Solution: The Initialize call must complete a real, successful API request to detect the response shape. First run your token fetch call separately to get a fresh access_token, then paste that real token value into the Authorization header temporarily for initialization. Also fill in a real phone number in E.164 format and your actual project_id and app_id. After Initialize succeeds and fields are detected, clear the hardcoded values and set them back to Dynamic parameters.

Message delivery fails silently — no error in Bubble logs but Sinch shows FAILED status

Cause: The channel specified in channel_priority_order is not available for the recipient (e.g., WhatsApp-only with a number not registered on WhatsApp), and no SMS fallback is included.

Solution: Always include 'SMS' as the last item in your channel_priority_order array. For example: ['WHATSAPP', 'SMS'] or ['RCS', 'WHATSAPP', 'SMS']. This ensures Sinch falls back to SMS if the preferred channel is unavailable. Without the SMS fallback, if WhatsApp delivery fails, the message is simply not delivered — Sinch does not return an error to Bubble in this case.

Backend Workflow not available — 'Workflow API is not enabled' message in Bubble

Cause: Your Bubble app is on the Free plan, which does not include Backend Workflows (API Workflows).

Solution: Upgrade your Bubble app to the Starter plan ($32/month) or higher. Go to Settings → Plans in your Bubble editor. Once on a paid plan, navigate to Settings → API and toggle on 'This app exposes a Workflow API'. Backend Workflows will then become available in your editor sidebar.

Best practices

  • Always store your Sinch Key Secret in the API Connector with the 'Private' checkbox enabled — never put it in a visible header or pass it through a frontend workflow parameter.
  • Cache the Sinch access_token in a Bubble data type with an expires_at timestamp set to 50 minutes from the fetch time (10 minutes before actual expiry). Check this timestamp before every message send and only fetch a new token when the cached one has expired.
  • Include 'SMS' as the last fallback channel in every channel_priority_order array. Channels like RCS are region-limited and device-specific; a message sent without an SMS fallback can fail silently for a large portion of recipients.
  • Store phone numbers in E.164 format (e.g., +12125551234) in your Bubble database from the moment users enter them. Formatting numbers at send time adds complexity and is a frequent source of delivery failures.
  • Set privacy rules on your Sinch Token data type in Bubble's Data → Privacy tab. Since this type contains Bearer tokens, the 'Everyone else can see' option should be off — only Backend Workflows need to read and write these records.
  • Use Bubble's Logs tab under 'Workflow logs' to debug each run of the sinch-send-message Backend Workflow. Expand individual actions to see the raw API response from Sinch, including message IDs you can cross-reference in the Sinch Dashboard.
  • Monitor Workload Units (WU) usage if you are sending high volumes of messages. Each Backend Workflow run — including the token check, optional token fetch, and message send — consumes WU. If you are sending thousands of messages, consider batching sends and evaluating Bubble's WU pricing at your expected volume.
  • Use separate Sinch Conversation Apps for development and production environments. This prevents test messages from appearing in your production Sinch logs and allows you to configure test phone numbers in the dev app without affecting production sender configuration.

Alternatives

Frequently asked questions

Does the Sinch integration work on Bubble's Free plan?

No. The Sinch Conversation API requires OAuth 2.0 token management, which must be handled in a Backend Workflow to keep your Key Secret server-side. Backend Workflows (API Workflows) are only available on Bubble's paid plans starting at Starter ($32/month). On the Free plan, you cannot safely implement this integration — you would need to expose the Key Secret client-side, which is a security risk.

Why do I need two API Connector calls instead of just one?

Sinch's Conversation API uses short-lived OAuth 2.0 Bearer tokens rather than a static API key. Before you can send a message, you must first exchange your Key ID and Key Secret for a Bearer token. That token expires after roughly one hour, so your integration needs to handle fetching fresh tokens periodically. Two separate API Connector calls — one for the token endpoint, one for the messages endpoint — map cleanly to this two-step process.

Can I use the legacy Sinch SMS API instead to avoid the token complexity?

Yes, if you only need SMS (no WhatsApp or RCS). The legacy API at api.sinch.com/xms uses a Service Plan ID and API Token with HTTP Basic auth — static credentials that never expire. This is simpler to set up in Bubble's API Connector (Basic auth, no token refresh). The downside is you lose access to WhatsApp, RCS, and channel-fallback routing, which are only available in the Conversation API.

What phone number format does Sinch require?

Sinch requires E.164 format: a plus sign, the country code, and the full national number with no spaces, dashes, or parentheses. For US numbers: +12125551234. Store numbers in this format in your Bubble database. If users enter numbers in local format, you need to clean and reformat them before passing to the Sinch API — incorrect formatting results in delivery failures without clear error messages.

How do I know if a message was actually delivered?

Sinch's messages:send endpoint returns a message_id immediately — this only confirms the message was accepted by Sinch, not delivered to the recipient. For delivery confirmation, check the Conversation → Logs section in the Sinch Dashboard. You can also set up a Sinch webhook to receive delivery status updates and process them in a Bubble Backend Workflow, though this adds additional setup complexity.

What happens when the access token expires mid-workflow?

If your cached token expires while a workflow is in progress, the messages:send call returns a 401 Unauthorized error. Your Backend Workflow will log this error in Bubble's Logs tab. To prevent this, set the expires_at timestamp to 50 minutes from the token fetch time (10 minutes before actual expiry) as a safety buffer. The token-check step in your workflow will then fetch a fresh token before the old one expires, avoiding mid-workflow failures.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Integrations are where projects stall

We wire Bubble integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.