Looking to build a brand-new connector type from scratch instead of configuring one of the existing ones? See Build a TMS Plugin. This guide covers only the connectors Phrase already supports.
Quickstart
The simplest call that confirms your setup works is listing the connectors your account can already see. Run this before anything else:200 response with a JSON list confirms three things at once: your token is valid, your account can reach the connector endpoints, and you have the access rights to read them. An empty list is still a success; it just means no connectors exist yet. If this call fails, fix it before moving on, because every step below depends on it. A 401 points to the token (see Prerequisites); a 403 points to your role or access rights (see Access-denied (403) on connector creation).
Prerequisites
Authentication setup itself is a link out on purpose, so this list stays short. You only need a valid token and the rights above to begin.
Two different APIs, easy to confuse
Now that you are connected, keep this distinction straight for the rest of the guide. Phrase has two separate API surfaces that both use the word “connector,” and it is easy to reach for the wrong one:- The Connectors API only moves file content through a connector that has already been set up: listing, uploading, downloading, and converting files inside a connector’s remote storage. It has no endpoints to create, edit, or delete a connector itself.
- The TMS API (this guide) owns the connector’s actual lifecycle: creating a new connector, listing your existing ones, viewing or editing a connector’s configuration, deleting it, and checking its sync status. This is where you set up a new Google Drive, GitHub, Amazon S3, WordPress, or Marketo connector.
Worked example: set up a connector end to end
A typical connector setup flow looks like this:- Confirm the connector does not already exist. List existing connectors and check by name and type, so you avoid creating duplicates if a previous attempt errored.
- For OAuth-based connector types (Google Drive, GitHub, Box, Salesforce, and others, listed under Set up an OAuth connector), walk the user through authorizing access to the third-party account.
- Create the connector with the fields that type requires.
- Check the connection status, and fix credentials if it is rejected.
- Optionally, monitor sync status and browse what the connector has picked up.
The connector lifecycle endpoints
All connector lifecycle operations live under/api2/v1/connectors on the TMS API:
Once a connector is created, keep a reference to its
uid. You need it to view, edit, delete, or check the status of that connector later, and it is what you use to link directly to the connector’s page in the TMS UI (/tms/connectors/edit/{uid}).
A connector being successfully created is a different thing from its connection being successfully tested. Creating or editing a connector does not automatically verify its credentials, except for
MAGENTO and TYPO3 connector types, which always run a live connection test. For every other type, pass connectionTest=true as a query parameter on POST or PATCH to run one explicitly. Otherwise a connector with entirely wrong credentials can be created successfully and only fail later. If a connection test reports an error status (for example GENERAL_ERROR or UNAUTHORIZED), the connector object still exists, so you usually need to go fix its credentials rather than starting over.Set up an OAuth connector
Many connector types authenticate via OAuth 2.0 rather than a plain username and password or API key. Setting one up requires walking the end user through a browser-based authorization step before the connector can be created.Which connector types use OAuth
These types require the authorization flow described below:GITHUB, GITHUB2, BITBUCKET, BOX, ONEDRIVE, SHAREPOINT, GOOGLE, GOOGLE_DRIVE2, SALESFORCE, VERBIS, HUBSPOT, ZENDESK, CONTENTFUL, CONTENTFULENTRYLEVEL, CONTENTFUL2.
The authorization flow
1. Get a one-time state token
state token that correlates your authorization attempt with the eventual callback.
2. Get the authorization page URL
{type}must be the exact sameConnectorTypeenum value you will use to create the connector, not an abbreviation, and not a differently-cased variant. This matters more than it sounds. For example, Google Drive’s correct type isGOOGLE_DRIVE2.GOOGLE_DRIVEdoes not exist as a type, andGOOGLEis a different, separate connector type. Calling this endpoint withGOOGLEreturns200successfully, but authorizes against the wrong provider configuration, and will break connector creation later. A400response here almost always means the type value is wrong, not that a parameter is missing.hostPrefixshould be the bare TMS hostname (host only, no scheme or path, for exampleqa.memsource.com).
{state}with the token from step 1.{redirectUri}with<TMS host>/web/connector/receiveConnectorAuthCode(this exact path is correct for every provider; do not vary it, and do not guess an alternative like/tms/...).
{state} or {redirectUri} text, since the provider will reject it outright.
3. Let the user authorize, then poll for the code
Once the user completes the provider’s sign-in and consent screen, their browser is redirected to the callback URL above with the real authorizationcode attached. That callback page auto-submits the code server-side and the URL reverts within seconds, too fast to copy by hand.
Instead, poll for it:
code (not null).
If the user reports landing on the callback page with no code and no visible error, this is usually a stale or reused state token. Restart from step 1 with a fresh one.
4. Create the connector
Create the connector using the code you polled for, following the type-specific fields documented in the API reference.GitHub Apps (GITHUB2) need one extra step
GITHUB2 uses GitHub’s newer “GitHub App” model rather than a classic OAuth App, which has two extra requirements beyond the flow above.
The Phrase GitHub App must be installed on the user’s GitHub account or organization. OAuth sign-in alone does not install it. Direct users to install it here, ideally alongside the authorization link rather than only after a failure:
login and tempLocalToken fields that the standard code exchange does not provide:
{ "localToken": "...", "logins": [...] }. If logins has more than one entry, ask the user which GitHub org or account to connect. Then create the connector with:
code or redirectUri directly to the create call for GITHUB2. That request shape is for classic GITHUB connectors only.
Google Drive (GOOGLE, GOOGLE_DRIVE2) need oauthClientId too
Both types’ create payload requires an oauthClientId field in addition to code and redirectUri. The create request fails without it.
Salesforce (SALESFORCE) specifics
Salesforce differs from every other OAuth type in two ways that are not obvious from the generic flow above.
hostPrefix means something different for Salesforce
For every other type, hostPrefix in step 2 is just the TMS hostname, used to build the TMS-side redirect URI. For Salesforce, connectorAuthPage instead builds the third-party authorize URL as https://{hostPrefix}.salesforce.com/services/oauth2/authorize?..., so hostPrefix here is Salesforce’s own login-domain prefix, not the TMS host.
Salesforce has required “My Domain” (*.my.salesforce.com) for all orgs for years, including every Developer Edition org (any domain ending -dev-ed). If the org identifier you have does not already end in .my (for example d3x000002kko8uao-dev-ed), append it yourself (d3x000002kko8uao-dev-ed.my) rather than sending it as-is. Only use a bare login or test prefix (no .my) if you have confirmed the org still uses the legacy non-My-Domain login page. Sending the identifier without .my produces a net::ERR_CERT_COMMON_NAME_INVALID browser error.
salesforcePublishStrategyType is required
The create call fails without this field. Its only valid values are:
PUBLISH: translated content is published live immediately.DRAFT: translated content is saved as a draft, not published live.SAME_AS_LATEST_TRANSLATION: mirrors the publish state of the most recent translation.
PHRASE connectors are the exception
The PHRASE connector type (which connects TMS to Phrase Strings, not another TMS instance or a third party) has a code-shaped field but is not part of this OAuth flow. It has no third-party OAuth provider registered, and calling connectorAuthPage for it returns an empty url by design. Its authorization is instead resolved server-side from your own authenticated identity. Attempt creation directly with the connector’s base fields plus its Strings-specific fields (phraseTmsOrganizationId and phraseTmsOrganizationName).
Troubleshooting
Access-denied (403) on connector creation
A403 or access-denied response when creating a connector has two unrelated causes that share the same generic exception. Always read the exact error message text, since that is the only way to tell them apart.
1. Role and access rights
Creating a connector requires the ADMIN or PROJECT_MANAGER role, and a separate access right called “Modify global server settings”. Having the ADMIN role does not guarantee this right is enabled; it is an independent per-account setting. If your error message is a generic access-denied with no further detail, check this first.2. Per-connector-type subscription entitlement
Some connector types are gated behind their own subscription add-on, independent of your role or access rights:AEM_PLUGIN, CONTENTFUL, HUBSPOT, OPTIMIZELY, TRIDION, KENTICO_KONTENT, BRAZE_MULTILANG, CONTENTSTACK, MARKETO, and ZENDESK each require a separate Phrase subscription add-on.
If the error message literally says something like “<TYPE> is not enabled”, this is not a permissions problem at all. Your organization’s Phrase subscription does not include that connector’s add-on. This is fixable through your subscription or billing, not through any access-rights toggle.
Per-connector-type field quirks
The generic connector-creation schema only documents the common base fields (name, type, sourceUrl, defaultRemoteFolder, encodedDefaultRemoteFolder, commitMessage). It does not reliably surface each connector type’s own extra fields. A handful of types have field names that do not match what you would naturally guess.
Amazon S3 (AMAZON_S3)
Fields are exactly apiKey, apiSecret, and amazonIamRole, not AWS’s own naming (accessKeyId and secretAccessKey). There is no region field: the region is embedded directly in the bucket hostname (for example integrations-plugins.qa.eu-west-1.s3.memsource.com).
Marketo (MARKETO)
You need four things to create a Marketo connector: the API key, the API secret, the API identity URL, and how the customer wants “Create translations” to work. Use the TMS UI’s own field labels when asking for credentials (“Marketo API key”, “Marketo API secret”, and “Marketo API identity URL”) rather than Marketo’s native OAuth terminology (“Client ID”, “Client Secret”, “Munchkin ID”). They map directly to the API’s field names, but the host value must be sent as identityURL in the request body. host is a hidden internal field name and is silently ignored if you send it instead.
The identity URL follows the format https://<munchkin-id>.mktorest.com/identity, for example https://063-RVK-838.mktorest.com/identity. Find your own instance’s value in Marketo Admin, under Integration then Web Services.
The “Create translations” mode field is marketoConnectorType, and its values are not dynamic or static as you might expect. They match the two options shown in the TMS UI:
SEPARATED_ASSET(“as separate documents”): translations are created as siblings of the original document, with the locale code appended to the title (for example Black Friday promo [de-de]).SEGMENTED_DYNAMIC_CONTENT(“as segmented dynamic content”): translations are stored within the original document, with each segment associated with a target locale.
apiKey, apiSecret, host (sent as identityURL), and marketoConnectorType. Segmentation mapping (marketoSegmentationMapping) is optional at the API level even when using segmented dynamic content mode.
Adobe Experience Manager (AEM_PLUGIN)
Beyond the base fields: host (required), plus optional basicAuthUserName and basicAuthPassword (used specifically for live preview, not the main connection), forcedHttps (boolean), and urlRewriteFind and urlRewriteReplace. Not OAuth-based.
WordPress (WORDPRESS)
WordPress connector credentials are not your normal WordPress admin login. They come from the Phrase or Memsource Connector plugin’s own settings page on the WordPress site:
GitHub (plain GIT type, credential-based)
If you are connecting to a github.com (or GitHub Enterprise) host using the plain GIT connector type (not GITHUB or GITHUB2), note that GitHub has rejected real account passwords for Git-over-HTTPS since August 2021. The password field must be a Personal Access Token, not your actual account password. An UNAUTHORIZED response for a GitHub-hosted GIT connector is almost always this.
Contentstack (CONTENTSTACK)
Send contentStackRegion alongside contentStackAuthType, apiKey, and sourceLang (the fields the schema does mark required) on every create request. Valid values are NORTH_AMERICA, EUROPE, AZURE_NORTH_AMERICA, AZURE_EUROPE, GCP_NORTH_AMERICA, and CUSTOM. Pick whichever matches where your Contentstack organization is hosted; NORTH_AMERICA is the default region for accounts that have not chosen a specific one. If a CONTENTSTACK create request returns a 500, check for this field before assuming a platform outage.
Types not listed here
For any connector type not covered above, inspect its create-connector request schema directly (use the full schema view in the API reference, not the summarized one) before assuming what fields it needs. Acode and redirectUri field pair means it is OAuth-based (see Set up an OAuth connector); anything else (a token, an API key, or host and credentials) means it is not.
Get more help
If a connector is still failing after the checks above:- Check the Phrase status page to rule out a platform incident before deeper debugging.
- For Phrase-side questions (roles, access rights, subscription add-ons, API behavior), contact Phrase support.
- For third-party-side questions (a rejected
redirect_uri, a GitHub App installation, a Salesforce org domain), work with whoever manages that third-party application’s configuration. Phrase support cannot change another provider’s registered OAuth app.
Next steps
Automate project creation
Have a working connector watch its remote storage and create translation projects automatically.
Build a TMS Plugin
Build a new connector type from scratch when none of the supported systems fit.
Last updated for the TMS API as documented in the API reference. Track API changes in the changelog.