docs
/
AI skills

Connect an integration

Connect an outside service (an email provider, a carrier, an AI key, a database, a marketplace) on the business's own account. Pick the provider, let the person enter the credentials, test with the provider's own answer, then switch it on with the right status and priority. Shows which screens own which services, and what an inactive config switches off.

An integration is one config record for one provider: data.provider names the provider class (SendGridProvider, ShippoProvider, OpenAIProvider…), data.status says whether it is in service, data.priority ranks it against others that can do the same job, and the rest of data holds that provider's settings and keys. The platform picks a config by what the job needs. Nothing points at a config by id.

Most services work on a new business with no config at all, on the platform's own account. Whose account a service runs on (the platform's, a sub-account, or the business's own), and what each costs, is explained in How integrations work and Your Appmint plan, credit, usage and services. The list of providers is the Integration catalog. The person's own walkthrough is Bring your own API credentials, gateway and email.

Use the job's own page first

Many services are connected on their own screen, with steps this page doesn't repeat:

The jobGo to
Card payments, PayPal, pay laterTake payments on the site
Hosted mailboxes, a sending domain, the sender addressBusiness email and the sending address
Reading a support mailbox (IMAP, Microsoft 365)Shared inbox
Carrier rates and labelsShipping rates and settings
Facebook, Instagram and other social accountsSocial posting and inbox
Facebook lead adsInbound lead channels
Phone numbers and calls; SMS registration; WhatsAppBusiness phone, SMS number registration, WhatsApp messaging
Amazon, eBay, Google Shopping and other sales channelsList a product on a sales channel
Turning a platform service on (its agreement)Your Appmint plan, credit, usage and services
Google Analytics or the Meta Pixelnot an integration: Google Analytics and the Facebook Pixel

Use this page for anything else, and to check, test, switch off or rank any config.

Ask first

  • Which service, for what job? "Send our email through SendGrid", "use our OpenAI key for AI".
  • Do they already have an account with that provider? The person signs in to it to get the keys. The AI never asks for a key, secret, token or password in chat, and never types one.
  • Their own account, or the platform's? Without a config of their own, the platform's account is used and billed to their balance. Their own account moves the provider's bill to them.
  • Test or live keys? Use test keys first where the provider has them.
  • Is something of theirs already connected for this job? Check step 1 before adding a second.

Steps

1. Integrations: what is there now

List the business's configs with repo_find on config. Report only data.name, data.provider, data.status and data.priority.

A config record holds the keys. repo_find returns every field, secrets included. Never repeat, summarise or copy a key, secret or token out of it, and never put one in a message, a note or another record.

Whether each platform service is running on the business's own account or the platform's: call_appengine GET /usage/shared (account: "own" or "shared"). For payments: GET /storefront/payment-gateways, which shows public fields only.

On screen: Configuration › Integrations (/integration-config). It has three tabs: Configurations (the list, with Edit, View JSON, Test and Delete on each row), Integration Builder (every provider, to make a new config) and API Playground.

Hands on: what exists for the job, by name and status. Check: the person sees the same rows on Configurations.

2. Pick the provider

call_appengine GET /upstream/integration-types lists every provider (57 on a current engine). Each one has:

FieldWhat it tells you
nameThe provider class, e.g. SendGridProvider. This goes in data.provider.
typeEmail, Payment, AI, Database, SocialMedia, Marketplace, GOOGLE, MICROSOFT or Integration
useCasesThe jobs it can do, e.g. ["Email", "Transactional Email", "Marketing"]
configSchemaIts settings form: each field's title, and required for the ones it must have. format: "password" marks a secret.
operationWhat it can be asked to do (sendEmail, getRates, test…). A config is used for a job only if its provider lists that operation.

Tell the person which fields they will need from the provider before they start, from configSchema.required.

Hands on: the provider name.

3. Setup wizard or Integration Builder: the person connects it

Stop: this is the person's to do. They enter the credentials on the screen. Send them there with the provider named.

  • Setup wizard (/setup-wizard) has its own connect flow for Stripe, PayPal, Twilio, Facebook, Google, TikTok, Pinterest, LinkedIn and X (Twitter). Most are a sign-in to the provider rather than a key to paste. Each also has Or enter API credentials manually. Use the wizard for these.
  • For everything else: Integrations › Integration Builder › search for the provider › fill in its form › Save. The form is the provider's configSchema plus the config's own fields (name, priority, status).

What the builder saves:

  • data.name: "<Provider> Configuration" until changed. Give it a clear, unique name (sendgrid-live). The running copy of an integration is kept under provider plus name, so two configs for one provider need different names.
  • data.status: inactive. A new config from the builder is never live on save.
  • the provider's fields as typed.

An inactive config switches that job off, the platform's account included. While a business has configs for a provider or a job and none of them is active or use-platform, the platform's own account is not used for it either (appengine upstream/upstream.service.ts: leavesPlatformOpen, mayUsePlatform, getIntegrationByOperation). So a SendGrid config saved and left inactive stops the business's email going out through the platform. The same goes for an AI key, a carrier, SMS. Finish step 5 the same day, or delete the config.

Hands on: the config's id (sk), once saved. Check: it is on Configurations with status inactive.

4. Test it

Testing runs the provider's own test operation against the provider with these credentials. For most providers it only checks that the credentials are accepted; it doesn't send, charge or post.

  • On screen: the row's Test on Configurations, or Test in the builder. It sends the form's values as they are, saved or not, whatever the status.
  • For the AI: call_appengine POST /upstream/call/<provider name>/test with { "data": null, "config": <the config's data> }. Build config from the record you read in step 1 and send it only in this call.

What comes back is the provider's own answer, not just a status code. Tested on a local engine:

RequestAnswer
POST /upstream/call/OfflineProvider/test with the config's data{ "success": true, "message": "Offline payment provider is ready", … }
POST /upstream/call/<config id>/test with {}, on an inactive config404 not_found. By id only active configs are used.
POST /upstream/call/<provider name>/test with {}, with no active config of the business's own404 not_found, or the platform's config is tested instead when the platform has one. Always send config.

A test can fail with HTTP 200: read the body. error, success: false, or status: "failed" is a failure. A wrong key typically reads like 401 API key is invalid; an account problem like 429 You have no credits remaining. Say which one it is: the key, the account, or the settings.

Use /upstream/call/…/test. The older POST /upstream/test/<provider>/<operation> route fails before it reaches the provider, whatever is sent: tested, it answers 400 Cannot read properties of undefined (reading 'data') (appengine upstream/upstream.service.ts 897–923).

Hands on: the test's answer. Check: a passing test says so in the provider's words. Don't call a config working on a save alone.

5. Integrations: switch it on

Stop: making it active moves that job onto the business's own account straight away: the next email, label or AI call goes through it and is billed by the provider. Say which jobs move and wait for yes.

The person sets Status on the config's form and saves. Or the AI, after the yes, uses repo_update on config with only the fields that change, e.g. patch: { "status": "active" }. repo_update keeps every other field (the keys stay put). Never resend the whole record to change one field.

data.statusWhat it means
activeIn service. A config with no status counts as active, so one written without a status is live at once.
inactiveSwitched off. It blocks the platform's account for the job too (step 3 warning).
deprecatedRetired. Treated like inactive.
use-platformKeep the record and its keys, but run the job on the platform's account. The way back from "ours" to "yours" without deleting anything.
FieldWhat it does
data.priority0–100, 1 when unset. When several active configs can do the same job, the highest runs. It is the only thing that picks between them.
data.sendOutgoingOn mail providers. false means this config never sends the system's outgoing mail. Unset means yes.
data.syncIncomingOn mailbox providers (IMAP, Microsoft). false means its mail isn't read in. Unset means yes.

A save or delete takes effect on the next call: the running copy of that integration is dropped and rebuilt from the new record. There is nothing to restart.

Hands on: the status and priority as saved. Check: repo_find_one on the config shows data.status and data.priority as asked. Then try the job once: the person sends themselves a test email, quotes a label, asks the AI something. GET /usage/shared now shows that service on account: "own".

Switching off, going back, removing

They wantDo
Stop using their account, carry on with the platform'sstatus: "use-platform"
Stop the job altogetherstatus: "inactive" (and know it also stops the platform's)
Remove itDelete on the row, or repo_delete on config. With no config left, the platform's account is used again. Deleted configs don't go to Trash.

Each is a Stop: it changes how the business's email, payments or AI run from the next call.

When it's done

Tell the person:

  • the provider, the config's name, and whether it is test or live;
  • what the test said, in the provider's words;
  • its status and priority, and which jobs now run on their account;
  • where to change it: Configuration › Integrations › Configurations.

What it can't do yet

  • No connection status on its own. A config shows only its saved status. Whether the keys still work is known only by testing (step 4) or by a job failing.
  • A new config can quietly switch a job off while it is inactive (step 3 warning).
  • POST /upstream/test/… doesn't work (step 4 note). Use /upstream/call/<provider>/test.
  • No arbitrary API. Only the providers in the list can be connected. Your own service needs a provider built for it, or a server of your own calling Appmint: see Bring your own API credentials.
  • Config names aren't checked. Spaces and duplicates are accepted on save (tested). Keep names unique per provider yourself.

Don'ts

  • Don't ask for, type, paste or repeat a key, secret, token or password. The person enters them on the screen.
  • Don't leave a new config inactive "for later". It turns that job off.
  • Don't write a config without status. It goes live at once.
  • Don't resend a whole config to change its status. Patch the one field.
  • Don't call a config working until its test passes and the job has been tried once.
  • Don't connect a service here when the job has its own page (the table at the top).