> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mithunai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Connect your tools to AI employees

> Connect Zendesk, Jira, Datadog, Sentry, PagerDuty, HubSpot, Slack, QuickBooks, Xero, Ramp, Okta and more to AI employees with credentials you create.

You can connect Zendesk, Freshdesk, Intercom, Jira, Jira Service Management, GitHub, Grafana Cloud,
Datadog, Sentry, PagerDuty, HubSpot, WordPress, X, LinkedIn, Google Search Console, Slack, Stripe,
QuickBooks Online, Xero, Ramp, Expensify, Okta, Google Workspace, Microsoft Entra ID, Gmail and Microsoft
Outlook to AI employees with credentials you create yourself; the support inbox's email and the other vendors
still need a vendor app.

> [!WARNING]
>
> **Beta, and not yet run against a real account.** These connectors are built and tested against
> recorded vendor answers; none has yet been used with a customer's live account. Try one on a test
> project or sandbox first. Never send a token to MITHUNAI support. MITHUNAI Team is switched off by
> default and your deployment's operator turns it on: access on request.

These vendors let you create a token yourself, so an AI employee can work in them:

| Employee | Tool | Connection | What it does there |
| - | - | - | - |
| Support | Support inbox, hand-off | **Zendesk**, **Freshdesk** or **Intercom**, one at a time | Posts the approved reply to the ticket -- as an internal note by default -- and hands a ticket to your team as an internal note |
| IT service desk | Ticketing | **Atlassian** (Jira or Jira Service Management) | Opens an issue or a service request, comments on one, and marks it resolved |
| DevOps | Monitoring and deploys | **Grafana Cloud** or **Datadog**, **Sentry** and **GitHub** | Reads error rate, latency and log lines; the Sentry issue behind an alert; recent deploys. Read-only |
| DevOps | On-call incidents | **PagerDuty** | Reads the incident and its timeline. An approved note goes on it, and an approved acknowledgement acknowledges it. Never resolves |
| DevOps | Incident ticket | **Atlassian** (Jira) | Posts the investigation to the incident's issue, or opens one; files an approved postmortem |
| Support, IT service desk, Finance | Team chat | **Slack** | Posts an approved message to the one channel you name. Outbound only |
| Marketer | Website and blog | **WordPress** | Saves an approved article as a draft on your site. Publishing it live is a second approval |
| Marketer | Social accounts | **X** and **LinkedIn** (Beta) | Posts an approved post on your X account or your LinkedIn page. Never deletes, messages, follows or likes |
| Marketer | Search performance | **Google Search Console** (Beta) | Reads clicks, impressions, position and index status, to find pages that lost search traffic. Read-only |
| Sales | CRM | **HubSpot** | Reads contacts, companies and deals. An approved update adds a note and sets the lead's status |
| Finance | Invoices and payments | **Stripe** | Reads invoice and payment status. Read-only |
| Finance | Accounting and bookkeeping | **QuickBooks Online** or **Xero**, one at a time (Beta) | Reads bills, invoices, contacts and accounts. An approved draft goes in your books, and an approved change re-codes one bill line. Never pays |
| Finance | Card spend and receipts | **Ramp** or **Expensify**, one at a time (Beta) | Reads card or expense transactions, receipts and Ramp's policy flags. Read-only |
| IT service desk | Identity and devices | **Okta**, **Google Workspace** or **Microsoft Entra ID** (Beta) | Reads people and groups. An approved change gives or takes away access, resets a password or MFA, or suspends or creates an account |

Every rule from before still holds:

* **Nothing changes without a person** where your policy says one is needed. An action that is
  rejected, or still waiting, sends nothing at all -- the token is not even opened.
* **A DevOps fix stays a proposal.** Rolling back or restarting is never sent to your systems, even
  when approved: the employee writes the evidence and the fix, and your team runs it.
* **The token goes to one host only** -- the site, account or stack the connection names -- and is
  never shown again. Every call is recorded in your audit log: which vendor, what was asked, and the
  answer's status code. Never the token, and never the content.
* **What a vendor sends back is treated as untrusted.** A ticket comment or a log line that says
  "ignore your instructions" is quoted as evidence and changes nothing.

## Connect a tool

1. Open **AI employees**, choose the employee under **Employees**, and find the tool under **Tools it
   works in**. Each one says whether it is connected and what connecting it does.
2. Choose **Connect**. The panel says where the token comes from, with a link to the vendor, and what
   it must be allowed to do. Use an account your team owns, not a person's own, and grant only what is
   listed.
3. Paste it in and choose **Save connection**, or pick one you already saved. Fill in the few settings
   it asks for, and choose **Connect and test**.

Only an owner or admin can connect or disconnect a tool. **Disconnect** stops the tool reaching that
vendor straight away; the saved connection is kept.

## Test a connection

**Test connection** on a connected tool makes one read at the vendor that changes nothing, and tells
you what it found: that it works, that the token was not accepted, that nothing answers at that
address, that the token is missing a permission, or that the vendor is not answering. Connecting a
tool runs it for you. Only an owner or admin can run it, and it is recorded in your audit log.

## A tool that is not connected

An approved action on it is recorded as **Not sent**. Nothing leaves MITHUNAI, and the wording stays
with you, under **Not sent**, to copy and use by hand. It is never recorded as done. A tool that says
**Not available yet** is one nothing can connect yet: it is not a connection anybody forgot to make.

Connected tools are kept with the rest of your organisation's settings, so they stay connected
across restarts and updates.

> [!NOTE]
>
> **A saved connection a tool is connected to cannot be deleted.** Deleting it in **Settings**, then
> **Connections**, is refused with a message naming the tool -- for example "the Support employee's
> support inbox". Disconnect the tool first, then delete the connection.

## Zendesk (Support)

1. Sign in to Zendesk as an admin and open **Admin Center**.
2. Go to **Apps and integrations**, then **APIs**, then **API tokens** (on older accounts, **Zendesk
   API**, with **Token access** turned on).
3. Choose **Add API token**, give it a description such as `MITHUNAI Support employee`, copy the
   token, and save.
4. In MITHUNAI, save a **Zendesk** connection with your Zendesk address
   (`your-company.zendesk.com`), the email of the agent the employee posts as, and the token.

When you connect the Support inbox you choose the **reply mode**:

* **Draft** (the default): an approved reply is posted on the ticket as an **internal note**, for an
  agent to read and send from Zendesk. Nothing reaches the customer until that agent sends it.
* **Public**: an approved reply goes to the customer as a public reply, and the ticket is set to
  *Pending*.

A hand-off is always an internal note, and sets the ticket to *Open*. Work must come with the Zendesk
ticket number as its reference; anything else is not sent.

> [!NOTE]
>
> Zendesk's API token acts as the agent whose email you give, with that agent's permissions. Zendesk
> now recommends OAuth for new integrations; API tokens still work, and are what MITHUNAI uses
> today.

## Freshdesk (Support)

1. Sign in to Freshdesk as the agent the employee should post as. It needs to be able to see and
   reply to your tickets, and add notes and tags.
2. Select your profile picture in the top right corner, then **Profile settings**.
3. Choose **View API key** (on some accounts it is shown under **Your API Key** on the right),
   complete the check Freshdesk asks for, and copy the key.
4. In MITHUNAI, save a **Freshdesk** connection with your Freshdesk address
   (`your-company.freshdesk.com`, or just `your-company`) and the key. The key is only ever sent
   there, and the address cannot be changed later. A custom portal address such as
   `support.your-company.com` is refused: use the `freshdesk.com` one.
5. On the **Support** page, connect the **Support inbox** and the **Hand-off** to it, and choose
   **Test connection**. Disconnect Zendesk or Intercom first if one is connected.

* **Draft** (the default): an approved reply is posted as a **private note** for an agent to send.
* **Public**: an approved reply goes to the customer as a reply. The ticket's status is left to
  Freshdesk's own automations.
* **Hand-off**: the ticket keeps its tags, gains `needs_a_person`, is set to *Open*, and gets a
  private note with the summary.
* **New tickets** are tickets with the status *Open* created after you [turn pick-up
  on](https://docs.mithunai.com/team/work-that-arrives-by-itself.md). A [test on past tickets](https://docs.mithunai.com/team/test-on-past-tickets.md) reads
  *Resolved* and *Closed* tickets from the last 30 days.

> [!NOTE]
>
> A Freshdesk API key acts as its agent, with that agent's permissions, until the agent's password
> is reset or the agent is removed. Each request counts against your Freshdesk plan's API limit.

## Intercom (Support)

1. Open Intercom's **Developer Hub** (in Intercom, **Settings**, then **Integrations**, then
   **Developer Hub**) and choose **New app**. Give it a name such as `MITHUNAI Support employee` and
   pick your workspace.
2. Open the app's **Authentication** page and copy its **Access token**. Under **Edit scopes**,
   check that it can read and write conversations, read admins, and read and write tags.
3. Note your workspace's **data region**: if you open Intercom at `app.eu.intercom.com` it is
   **Europe**, at `app.au.intercom.com` **Australia**, and otherwise the **United States**.
4. In MITHUNAI, save an **Intercom** connection with that region and the token. The token is only
   ever sent to that region's Intercom address, and the region cannot be changed later.
5. On the **Support** page, connect the **Support inbox** and the **Hand-off** to it, and choose
   **Test connection**. Disconnect Zendesk or Freshdesk first if one is connected.

* Replies and notes are posted **as the admin the token belongs to**: the app's owner. Choose that
  admin with care; the employee's notes appear under their name.
* **Draft** (the default): an approved reply is a **note** on the conversation. **Public**: it is a
  reply to the customer.
* **Hand-off**: the conversation gains the tag `needs_a_person` (created the first time) and a note
  with the summary. Its state is left as it is, so a snoozed conversation stays snoozed.
* **New tickets** are open conversations created after you turn pick-up on. A test on past tickets
  reads closed conversations.

## Jira and Jira Service Management (IT service desk, DevOps)

1. Signed in as the account the employee should act as, open
   [id.atlassian.com/manage-profile/security/api-tokens](https://id.atlassian.com/manage-profile/security/api-tokens).
2. Choose **Create API token** -- the plain one, not **Create API token with scopes**, which only
   works through a different address -- name it, pick an expiry, create it and copy it.
3. In MITHUNAI, save an **Atlassian** connection with your site address
   (`https://your-company.atlassian.net`), that account's email and the token. The same connection
   can serve Confluence and Jira knowledge sources.
4. Give the account, in the project: **Browse projects**, **Create issues**, **Add comments** and
   **Transition issues**. For a service desk it must be an agent on it.

When you connect Ticketing you give:

* **Project key** -- such as `IT` -- for new issues, and the **issue type** (default *Task*). Or, to
  raise **Jira Service Management requests** instead, the **service desk id** and **request type
  id**: both are numbers, shown by Jira's API at `/rest/servicedeskapi/servicedesk` and
  `/rest/servicedeskapi/servicedesk/{id}/requesttype` while you are signed in.
* **Resolved status** -- the name of the status that means done in your workflow (default *Done*;
  often *Resolved* in a service project). When a request is already a Jira issue and your knowledge
  answers it, the employee proposes a comment with the answer and moving the issue to this status.
  If your workflow has no single transition to it, the issue is left as it is.

## GitHub (DevOps deploys)

1. In GitHub, open **Settings**, then **Developer settings**, then **Personal access tokens**, then
   **Fine-grained tokens**, and choose **Generate new token**.
2. Set the **resource owner** to your organisation, **Repository access** to **Only select
   repositories**, and pick the repository that deploys the service.
3. Under **Repository permissions** set **Deployments** to *Read-only* and **Actions** to
   *Read-only*. Nothing else. Your organisation may need to approve the token.
4. In MITHUNAI, save a **GitHub** connection with the token.

When you connect it you give the **repository** (`owner/name`), and either the **environment** whose
deployments count (such as `production`), or the **workflow file** whose successful runs are your
deploys (such as `deploy.yml`).

## Grafana Cloud (DevOps logs and metrics)

1. In your Grafana Cloud stack, open **Administration**, then **Users and access**, then **Service
   accounts**, and choose **Add service account**. Give it the **Viewer** role.
2. On the service account, choose **Add service account token**, generate it and copy it.
3. In MITHUNAI, save a **Grafana** connection with your stack address (`your-company.grafana.net`)
   and the token.
4. Find the **uid** of your Prometheus and Loki data sources: open **Connections**, then **Data
   sources**, then the data source; the uid is the last part of the page's address.

When you connect Monitoring you give the Prometheus uid, the Loki uid, or both. The queries default
to the common names -- `http_requests_total`, `http_request_duration_seconds_bucket`, and a Loki
`service_name` label -- and you can give your own, writing `$service` where the alert's service name
goes. The error-rate query should return a fraction between 0 and 1, and the latency query
milliseconds. Only Grafana Cloud stacks are accepted: a self-hosted Grafana on your own network is
not reachable from MITHUNAI.

## Datadog (DevOps logs and metrics)

1. In Datadog, open **Organization Settings**, then **API Keys**, and copy a key (or create one).
2. Open **Application Keys** and create one. Under **Scopes**, give it only **timeseries\_query** and
   **logs\_read\_data**.
3. In MITHUNAI, save a **Datadog** connection: choose your **site** -- the part after `app.` in the
   address you sign in at, such as `datadoghq.com`, `us5.datadoghq.com` or `datadoghq.eu` -- and
   paste both keys. They are only ever sent to that site's API.

The queries default to APM's request metrics and to logs with `service:$service status:(error OR
warn)`; you can give your own when you connect Monitoring, writing `$service` where the alert's
service name goes. The error-rate query should return a fraction between 0 and 1, and the latency
query seconds. If both Grafana Cloud and Datadog are connected, logs are read from both and metrics
from the first that has any.

## Sentry (DevOps errors)

1. In Sentry, open **Settings**, then **Custom Integrations**, and choose **Create New Integration**,
   then **Internal Integration**.
2. Under **Permissions**, set **Issue & Event** and **Project** to **Read**. Nothing else.
3. Save, then copy the integration's **token** and its **client secret**.
4. In MITHUNAI, save a **Sentry** connection with the token and the client secret. Leave the address
   empty for `sentry.io`; give `https://de.sentry.io` for Sentry's EU region, or your own
   `https://sentry.your-company.com` for a self-hosted Sentry that is reachable from the internet.
5. Attach it to DevOps **Monitoring and deploys**, giving your **organization slug** -- the `acme` in
   `acme.sentry.io`.
6. The DevOps page now shows a **Webhook address** beside the connection. In Sentry, open the
   integration again, paste it as the **Webhook URL**, and turn on **Alert Rule Action**.
7. In each alert rule you want investigated, add the action **Send a notification via** your
   integration.

The client secret only checks that a webhook really came from your Sentry. Without it, the connection
still reads issues, but Sentry's webhooks are refused. A Sentry issue is read only for an alert
Sentry sent.

## PagerDuty (DevOps on-call incidents)

1. In PagerDuty, open **Integrations**, then **API Access Keys**, and create a key. PagerDuty has no
   key that can only add notes and acknowledge, so it is a full-access key: use a dedicated one, and
   revoke it if you stop.
2. In MITHUNAI, save a **PagerDuty** connection with the key and the email of the PagerDuty user that
   notes and acknowledgements are recorded as.
3. Attach it to DevOps **On-call incidents**. The DevOps page shows a **Webhook address** beside it.
4. In PagerDuty, open **Integrations**, then **Generic Webhooks (v3)**, and add a subscription with
   that address, for the events **incident.triggered** and **incident.resolved**.
5. PagerDuty shows the subscription's **signing secret** once. In MITHUNAI, replace the connection's
   token -- paste the key again, with the signing secret -- so PagerDuty's webhooks are accepted.

A triggered incident is investigated; a resolved one becomes a postmortem draft. Nothing resolves an
incident from MITHUNAI. Only PagerDuty's US service region (`api.pagerduty.com`) can be connected
today.

## Slack (Support, IT service desk, Finance)

1. At [api.slack.com/apps](https://api.slack.com/apps), create an app from scratch for your workspace.
2. Under **OAuth and Permissions**, add the bot scope `chat:write`, and install the app to your
   workspace. It is your own workspace's app, so it needs no review by Slack.
3. Copy the **Bot User OAuth Token**, which starts `xoxb-`, and invite the bot to the channel.
4. Connect **Team chat** on the employee's page, and name the **channel**.

Every approved message goes to that one channel, whatever the message says, and Slack's mention and
link markup in a message is shown as plain text. It is outbound only: nothing is read from Slack, and
nothing can be approved from there.

## WordPress (Marketer)

1. In WordPress, open **Users**, then your profile, and add a new password under **Application
   Passwords**. Use an account that can create and publish posts, such as an Editor.
2. Connect **Website and blog** on the Marketer's page with your site's https address, the username
   and the application password.

MITHUNAI reaches your site only over https, on the normal port, and never at an address on a private
network. A site in a subfolder is not supported yet. An approved article is saved as a draft;
publishing it is a second approval.

## X (Marketer)

X signs each request with four values. The account that posts must own the developer app.

1. Sign in to the [X developer portal](https://developer.x.com/en/portal/dashboard) **as the account
   that posts**, such as your company's account, and create a project and an app. The Free tier
   allows 500 posts a month.
2. In the app's **User authentication settings**, set **App permissions** to **Read and write**.
   Save.
3. Open **Keys and tokens**. Copy the **API Key and Secret** (regenerate them if you did not keep
   them). Under **Access Token and Secret**, choose **Generate**: generate them *after* step 2, or
   they can only read.
4. In MITHUNAI, save an **X** connection with the API key, the API key secret, the access token and
   the access token secret, then connect **Social accounts** on the Marketer's page. It takes no
   options.

None of the four is sent to X: they sign each request. They do not expire; regenerating any of them
in the portal stops the connection until you replace it. **Test connection** reads the account the
token belongs to and changes nothing.

## LinkedIn (Marketer)

LinkedIn lets an app post on a company page only with its **Community Management API**, which
LinkedIn reviews.

1. In the [LinkedIn Developer Portal](https://www.linkedin.com/developers/apps), create an app and
   associate it with your company page. A page administrator verifies it from the app's **Settings**.
2. Under **Products**, request **Community Management API** and wait for LinkedIn to grant it.
3. Open the [OAuth token generator](https://www.linkedin.com/developers/tools/oauth/token-generator),
   choose your app, select the scopes **w\_organization\_social** and **r\_organization\_admin**, and
   sign in as an **administrator** or **content administrator** of the page. Copy the access token.
4. In MITHUNAI, save a **LinkedIn** connection with the token, then connect **Social accounts** on
   the Marketer's page with your page's **organization id**: the number in its admin address,
   `linkedin.com/company/<number>/admin`.

**The token lasts 60 days.** Replace it before then with **Replace token**; an expired one fails
**Test connection**, which also says whether the person who made the token may post for that page.
A post's `#`, `@` and other markup characters are posted as plain text.

## Google Search Console (Marketer)

The Marketer reads Search Console as a service account that is a user of your property. It reads
only.

1. In [Google Cloud](https://console.cloud.google.com/), choose or create a project and enable the
   **Google Search Console API**.
2. Under **IAM and admin**, then **Service accounts**, create a service account. It needs no project
   role. Open it, then **Keys**, and add a **JSON** key. Keep the file.
3. In [Search Console](https://search.google.com/search-console), open your property, then
   **Settings**, then **Users and permissions**, and **Add user**: the service account's email address
   (`...@....iam.gserviceaccount.com`), with **Restricted** permission.
4. In MITHUNAI, save a **Google Search Console** connection by pasting the whole JSON key file, then
   connect **Search performance** on the Marketer's page with the **property** exactly as Search
   Console shows it: `sc-domain:example.com` for a domain property, or `https://www.example.com/` for
   a URL-prefix property.

Only the key file's address and private key are kept; the key signs a request for a read-only token
and is never sent. **Test connection** reads the property and says whether the service account was
added to it. Then choose **Check search performance** on the Marketer's page.

## HubSpot (Sales)

1. In HubSpot, open **Settings**, then **Integrations**, then **Private Apps**, and create a private
   app.
2. Give it the scopes `crm.objects.contacts.read`, `crm.objects.contacts.write`,
   `crm.objects.companies.read` and `crm.objects.deals.read`.
3. Copy its access token, which starts `pat-`, and connect **CRM** on the Sales page.

It reads a contact, its first company and up to three deals. An approved update adds a note to the
contact and sets its lead status. Qualification rules are written on the Sales page, not read from
HubSpot. An account brief reads a deal or company, up to three of its deals and five of its contacts,
with the same scopes.

## Gmail (Sales)

> [!WARNING]
>
> Domain-wide delegation lets the key act as **any** mailbox in your domain. MITHUNAI uses only the
> one mailbox you name, but use a service account for mail alone, apart from the IT service desk's,
> and delegate it these two scopes and nothing else.

1. In the [Google Cloud console](https://console.cloud.google.com/), pick or create a project, open
   **APIs and services**, then **Library**, and enable the **Gmail API**.

2. Open **IAM and admin**, then **Service accounts**, and create a service account for mail. It needs
   no roles in the project. On its **Keys** tab, choose **Add key**, then **Create new key**, then
   **JSON**, and keep the file. Note its numeric **Unique ID** (its client id).

3. In the [Google Admin console](https://admin.google.com/), as a super administrator, open
   **Security**, then **Access and data control**, then **API controls**, then **Manage domain-wide
   delegation**, and choose **Add new**. Enter the client id and these two OAuth scopes, separated by a
   comma:

   ```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
   https://www.googleapis.com/auth/gmail.compose,https://www.googleapis.com/auth/gmail.readonly
   ```

   `gmail.compose` saves drafts, and sends one if you turn sending on; `gmail.readonly` reads the
   thread a reply is drafted in. Both are needed: a scope that is asked for but not delegated makes
   every sign-in fail.

4. Connect **Email** on the Sales page: choose **Gmail**, paste the **whole JSON key file**, and give
   the **mailbox** follow-ups are drafted in -- such as your own address. Leave **Sending** off to
   save drafts only.

5. Choose **Test connection**. It signs in as that mailbox and reads its profile.

## Microsoft Outlook (Sales)

1. In the [Microsoft Entra admin center](https://entra.microsoft.com/), open **Identity**, then
   **Applications**, then **App registrations**, and choose **New registration** for mail alone,
   apart from the IT service desk's. Single tenant; no redirect address.

2. On its **Overview**, copy the **Application (client) ID** and the **Directory (tenant) ID**. Open
   **Certificates and secrets**, add a client secret, and copy its **Value**.

3. Open **API permissions**, choose **Add a permission**, then **Microsoft Graph**, then **Application
   permissions**, and add:

   | Permission | Why |
   | - | - |
   | `Mail.ReadWrite` | Read the message a reply answers, and save drafts |
   | `Mail.Send` | Only if approved drafts may be sent from MITHUNAI; else no |

   Then choose **Grant admin consent**.

4. An application permission covers **every mailbox in the tenant**. Limit it to your sales team's
   mailboxes with an [application access policy](https://learn.microsoft.com/graph/auth-limit-mailbox-access)
   in Exchange Online.

5. Connect **Email** on the Sales page: choose **Microsoft Outlook**, enter the tenant id, the
   application id and the client secret, and give the **mailbox**. Leave **Sending** off to save
   drafts only.

6. Choose **Test connection**. It signs in and reads that mailbox's Drafts folder.

With either, a draft is saved in that one mailbox and nothing is sent. With **Sending** on, a saved
draft is followed by its own approval to send it, and it is sent only if it is still addressed to the
person you approved -- add a recipient in your mailbox and it is not sent from here.

## Stripe (Finance)

1. In the Stripe dashboard, open **Developers**, then **API keys**, and create a **restricted key**
   with **Read** access to **Invoices**, and nothing else.
2. Copy it, which starts `rk_`, and connect **Invoices and payments** on the Finance page.

A secret key is refused. MITHUNAI only ever reads through this connection: no refund, payment or
reminder can be sent.

## QuickBooks Online (Finance)

QuickBooks has no token you can paste: you register **your own** Intuit app, and a person in the
company consents once.

1. In the [Intuit Developer portal](https://developer.intuit.com/app/developer/dashboard), create an
   app and choose the **Accounting** scope (`com.intuit.quickbooks.accounting`). Nothing else.
2. Under **Keys and credentials**, add your deployment's accounting redirect address to **Redirect
   URIs** -- your administrator gives it to you; it is the AI-employees address with
   `?integration=accounting`, such as `https://team.your-company.com/?integration=accounting`. Use
   the **Development** keys with a sandbox company while you try it; production keys need Intuit's
   app details filled in.
3. On the Finance page, connect **Accounting and bookkeeping**, choose **QuickBooks Online**, the
   environment (**Sandbox** or **Production**), and paste the app's **client id** and **client
   secret**.
4. Press **Connect to QuickBooks Online**, sign in as a company user who may add bills and invoices,
   and choose the company. You come back to the Finance page, connected. Press **Test connection**.

QuickBooks hands out a new refresh token with each access token; MITHUNAI stores it again, sealed,
each time. If a consent is revoked or unused for 100 days, press **Connect** again. QuickBooks has no
draft bills: an approved bill is **recorded unpaid**, and nothing here can pay it.

## Xero (Finance)

1. In [Xero's developer portal](https://developer.xero.com/app/manage), create a **Web app**.
2. Add the same accounting redirect address as its **Redirect URI**, generate a **client secret**,
   and copy the **client id**. The app asks for `offline_access`, `accounting.transactions`,
   `accounting.contacts.read` and `accounting.settings.read`. If Xero only offers its newer granular
   scopes for your app, tell your administrator: they are not asked for yet.
3. On the Finance page, connect **Accounting and bookkeeping**, choose **Xero**, and paste the client id
   and secret. Xero has one environment; use a **demo company** while you try it.
4. Press **Connect to Xero** and choose **one** organisation. An app connected to more than one is
   refused: connect a Xero app to the one organisation the Finance employee works in.

Everything it adds to Xero is a **draft**; a person approves it in Xero.

## Ramp (Finance)

1. In Ramp, open **Company**, then **Developer**, and create an app with the **client credentials**
   grant and only the scopes `transactions:read`, `receipts:read` and `users:read`.
2. On the Finance page, connect **Card spend and receipts**, choose **Ramp**, the environment
   (**Sandbox** for a Ramp sandbox, on `demo-api.ramp.com`), and paste the client id and secret.
3. Optionally set the **receipt threshold**: a charge at or below it needs no receipt.

Ramp is read only: no card, limit or transaction changes from here. A reminder to a cardholder goes
through Slack, after a person approves it.

## Expensify (Finance)

1. In Expensify, sign in as a domain admin and open the **Integration Server** page to get a partner user
   id and secret. The secret is shown once.
2. On the Finance page, connect **Card spend and receipts**, choose **Expensify**, and paste both.
3. Optionally set the **receipt threshold**: an expense at or below it needs no receipt.

Expensify is read only. It reads the last 31 days of expenses and whether each has a receipt. Nothing is
approved, returned or reimbursed from here.

## Okta (IT service desk)

> [!WARNING]
>
> An identity connection can change who signs in to what. Every change it makes always waits for a
> person, but connect a test org first, and give the token no more than it needs.

1. In the Okta Admin Console, create an administrator for MITHUNAI to act as -- a dedicated user is
   best -- with the **Organization Administrator** role, or a custom admin role that may manage users'
   lifecycle, reset passwords and authenticators, and manage group membership. **An API token acts
   with exactly the permissions of the administrator who creates it.**
2. Signed in as that administrator, open **Security**, then **API**, then **Tokens**, choose **Create
   token**, name it, and copy the value. Okta shows it once.
3. Connect **Identity and devices** on the IT service desk page: choose **Okta**, enter your Okta
   address -- such as `your-company.okta.com` -- and paste the token.
4. Optionally give a **group name prefix**, such as `app-`, so only those groups can be granted.
5. Choose **Test connection**. It reads the token's own administrator and changes nothing.

A password reset is Okta's own: Okta emails the person a link, and the link never reaches MITHUNAI.
An Okta custom domain is not supported yet; use the `okta.com` address. Okta expires a token that is
unused for 30 days.

## Google Workspace (IT service desk)

1. In the [Google Cloud console](https://console.cloud.google.com/), pick or create a project, open
   **APIs and services**, then **Library**, and enable the **Admin SDK API**.

2. Open **IAM and admin**, then **Service accounts**, and create a service account. It needs no
   roles in the project. On its **Keys** tab, choose **Add key**, then **Create new key**, then
   **JSON**, and keep the file. Note the service account's numeric **Unique ID** (its client id).

3. In the [Google Admin console](https://admin.google.com/), as a super administrator, open
   **Security**, then **Access and data control**, then **API controls**, then **Manage domain-wide
   delegation**, and choose **Add new**. Enter the client id and these OAuth scopes, separated by
   commas:

   ```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
   https://www.googleapis.com/auth/admin.directory.user,https://www.googleapis.com/auth/admin.directory.user.security,https://www.googleapis.com/auth/admin.directory.group.member,https://www.googleapis.com/auth/admin.directory.group.readonly
   ```

   All four are needed: a scope that is asked for but not delegated makes every sign-in fail.

4. Connect **Identity and devices** on the IT service desk page: choose **Google Workspace**, paste
   the **whole JSON key file**, and enter the **administrator's email** the service account acts as --
   a super administrator, or an administrator who may manage users and groups.

5. Optionally give a **group name prefix**, then choose **Test connection**. It signs in and reads one
   user.

Only the key file's address and private key are kept; the private key signs each sign-in and is never
sent. Google Workspace has no emailed reset: a password reset asks for a new password at the next
sign-in.

## Microsoft Entra ID (IT service desk)

1. In the [Microsoft Entra admin center](https://entra.microsoft.com/), open **Identity**, then
   **Applications**, then **App registrations**, and choose **New registration**. Single tenant; no
   redirect address.

2. On its **Overview**, copy the **Application (client) ID** and the **Directory (tenant) ID**.

3. Open **Certificates and secrets**, then **Client secrets**, choose **New client secret**, and copy
   its **Value** -- not its Secret ID. Note when it expires.

4. Open **API permissions**, choose **Add a permission**, then **Microsoft Graph**, then **Application
   permissions**, and add:

   | Permission | Why |
   | - | - |
   | `User.ReadWrite.All` | Look people up, create, block and sign them out |
   | `User-PasswordProfile.ReadWrite.All` | Ask for a new password at the next sign-in |
   | `GroupMember.ReadWrite.All` | List groups, and add or remove members |
   | `UserAuthenticationMethod.ReadWrite.All` | Remove sign-in methods for an MFA reset |

   Then choose **Grant admin consent**.

5. Connect **Identity and devices** on the IT service desk page: choose **Microsoft Entra ID**, and
   enter the tenant id, the application id and the client secret.

6. Optionally give a **group name prefix**, then choose **Test connection**. It signs in and reads one
   user.

Dynamic groups are not offered: their members come from a rule. An administrator's password or MFA
cannot be changed through this app unless it is also given a privileged directory role, which this
setup does not ask for.

## Not yet available

These say **Not available yet**. Each needs an app registered with the vendor, or a token kind
MITHUNAI does not take yet:

* **Microsoft Teams**, and approving from inside Slack.
* **ServiceNow** ticketing.
* **Salesforce**, and expense systems such as **SAP Concur** and **Coupa**.
* **Device management**, such as installing software on a laptop.
* Email for the support inbox.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.