# Meridian (/docs/workflows/integrations/meridian)

> For the complete documentation index, see [llms.txt](https://docs.tandemcx.ai/llms.txt). Any page on this site can be fetched as Markdown by appending `.md` to its URL.

<Callout type="info">
    **The Meridian integration is being rolled out.** If you don't see **Meridian** when you add an
    integration, it isn't on for your organization yet.
</Callout>

The Meridian integration connects Tandem to your co-op's Meridian Consumer Accounts API. Five
workflow nodes and one AI agent tool read and write member account data through it: find an
account, read a balance, check for an outage, report one, and check whether an account can set
up a payment arrangement.

Taking a card payment is a separate integration, **Meridian Payments**. See
[Taking a payment](#taking-a-payment).

## Setup

An organization can have several Meridian integrations, such as one for sandbox and one for
production.

### 1. Get your details from Meridian

Meridian issues these. Tandem does not generate any of them:

- **Accounts API URL** and **Payment gateway URL**, one pair per environment.
- **Client ID** and **Application ID**.
- **API token**, which starts with `LT:`.

Meridian only accepts calls from allowlisted addresses. Contact Tandem support for the
addresses to give Meridian.

### 2. Connect it in Tandem

On the **Integrations** page, click **Add Integration**, choose **Meridian** under **Contact
Center**, and fill in the form:

| Field                   | What to enter                                                                                      |
| ----------------------- | -------------------------------------------------------------------------------------------------- |
| **Name**                | A label for this connection, such as `Co-op (production)`.                                         |
| **Environment**         | **Sandbox** or **Production**. Defaults to **Sandbox**.                                            |
| **Accounts API URL**    | The `https://` address of the Consumer Accounts API. Leave `/api` off the end.                     |
| **Payment gateway URL** | The `https://` address of the payment gateway. Used to quote a convenience fee.                    |
| **Client ID**           | 1 to 20 letters or digits.                                                                         |
| **Application ID**      | 1 to 10 digits.                                                                                    |
| **API token**           | The token from Meridian. A leading `Bearer ` or `LT:` is removed for you, so either may be pasted. |

Both URLs must be public `https://` addresses. A trailing slash is dropped. Addresses that
resolve to a private or internal network are refused, both when you save and when a request is
sent.

Saving does not contact Meridian. Use **Test Connection** to check the connection.

### 3. Test the connection

Open the integration and click **Test Connection**. Tandem calls Meridian's health check, then
makes an authenticated call that lists Meridian's lookup tables. It tests the token that is
stored, so save a new token before you test it.

| Result                                                                                                  | What it means                                                                                                |
| ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `Connection successful`                                                                                 | Meridian is up and accepted the token.                                                                       |
| `Meridian rejected the token`                                                                           | Meridian answered `401` or `403`. The token is wrong, expired, or revoked.                                   |
| `Meridian health check failed`                                                                          | Meridian's health check answered something other than `200`.                                                 |
| `Meridian has no accounts API at that address. Check the Accounts API URL, and leave /api off the end.` | The health check answered, but the accounts API did not. Remove a trailing `/api` from **Accounts API URL**. |
| `Could not reach Meridian`                                                                              | The address did not answer. Check the URL, and that Meridian has allowlisted Tandem's addresses.             |

## Updating or removing the connection

- **Update it.** Open the integration and change any field. Tandem never shows the saved token
  again. Leave **API token** blank to keep the stored one. Changing either URL requires
  entering the token again.
- **Delete it.** This removes the stored token. Nodes and agent tools that point at it can no
  longer reach Meridian, so pick another integration in them first.

## Workflow nodes

The five nodes appear in the Node Library once the integration is on for your organization.
Each one has a **Meridian Integration** field that lists your Meridian integrations, and a
**Variable Prefix** that names the variables it writes: with the prefix `account`, a result
called `balance` is saved as `account_balance`.

**Account Number** has spaces and dashes removed, so `221-390 000` is sent as `221390000`.
Anything that is not then 1 to 19 digits takes `invalidInput`. An **Account Number** search in
Find Meridian Account works the same way.

Every node also has two exits that come from the platform. `invalidInput` is taken when a
required field is empty after variable substitution or a value is invalid. `fallback` is taken
when Meridian rejects the saved credentials, cannot be reached, rejects the request as invalid,
or returns any other error. The message names the cause, such as
`Meridian rejected the saved credentials. Update them on the Integrations page.`

### Find Meridian Account

Searches for member accounts.

| Field                      | What it does                                                                                                           |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **Search By**              | **Phone Number** (the default), **Account Number**, **Member Number**, **Meter Number**, or **Zip and Street Number**. |
| **Value**                  | What to search for. Supports `$(variable)`. For a phone search, blank uses the caller's number.                        |
| **Zip**, **Street Number** | The service address. Shown, and both required, for **Zip and Street Number**.                                          |
| **Variable Prefix**        | Prefix for the result variables.                                                                                       |

A phone number is reduced to digits. An 11-digit number that starts with `1` loses the `1`. A
phone search with no **Value** and no caller number takes `invalidInput`.

| Exit       | When                         |
| ---------- | ---------------------------- |
| `found`    | Exactly one account matches. |
| `multiple` | Several accounts match.      |
| `notFound` | No account matches.          |

On `multiple`, do not treat the first match as the caller's account. Ask which one they mean.
One phone number can belong to several households.

Variables, for `found` and `multiple`: `<prefix>_count`, `<prefix>_accounts`, and the first
match's `<prefix>_accountNumber`, `<prefix>_memberNumber`, `<prefix>_firstName`,
`<prefix>_lastName`, `<prefix>_isPrepaid`, `<prefix>_isDisconnected`, and
`<prefix>_onCutOffList`. `<prefix>_accounts` is a list of at most 10 accounts. Each holds
`accountNumber`, `accountType`, `accountStatus`, `serviceStreet`, and `serviceCity`, with no names
or member numbers for the other matches. On `notFound` only `<prefix>_count` and
`<prefix>_accounts` are saved.

### Get Meridian Account

Reads one account.

| Field               | What it does                                                                                |
| ------------------- | ------------------------------------------------------------------------------------------- |
| **Account Number**  | The account to read. Supports `$(variable)`, so it can come from Find Meridian Account.     |
| **Payment Amount**  | Optional, such as `100.00`. When set, Meridian quotes the convenience fee for that payment. |
| **Variable Prefix** | Prefix for the result variables.                                                            |

| Exit       | When                          |
| ---------- | ----------------------------- |
| `default`  | The account was read.         |
| `notFound` | Meridian has no such account. |

Variables: `<prefix>_accountNumber`, `_balance`, `_pastDueAmount`, `_minimumPaymentAmount`,
`_lastBillDate`, `_lastPaymentAmount`, `_isDisconnected`, `_canUseCreditCards`,
`_hasArrangement`, `_onCutOffList`, `_isPrepaid`, and `_convenienceFee`. Money values are
decimal strings such as `268.57`. `_convenienceFee` is an empty string when you set no
**Payment Amount**, when the account cannot pay by card, when Meridian returns no payment token
for it, or when the fee lookup fails.

### Get Meridian Outages

Checks an account for outages.

| Field                        | What it does                                                        |
| ---------------------------- | ------------------------------------------------------------------- |
| **Account Number**           | The account to check. Supports `$(variable)`.                       |
| **Include Resolved Outages** | Off by default, which returns active outages only. On returns both. |
| **Variable Prefix**          | Prefix for the result variables.                                    |

| Exit        | When                             |
| ----------- | -------------------------------- |
| `hasOutage` | At least one outage is returned. |
| `noOutage`  | None is returned.                |

Variables: `<prefix>_count`, and for the first outage `<prefix>_status`,
`<prefix>_description`, and `<prefix>_estimatedRestoration`. With no outage only the count is
saved.

### Report Meridian Outage

Reports an outage for an account.

| Field                     | What it does                                                                  |
| ------------------------- | ----------------------------------------------------------------------------- |
| **Account Number**        | The account to report for. Supports `$(variable)`.                            |
| **Reason**                | A reason code from the list configured in Meridian. Leave blank to send none. |
| **Note**                  | Free text for the crew, up to 500 characters.                                 |
| **Request Callback**      | Ask the co-op to call the member back.                                        |
| **Callback Phone Number** | Shown when **Request Callback** is on. Blank uses the caller's number.        |
| **Variable Prefix**       | Prefix for the result variable.                                               |

With **Request Callback** on and no number from either place, the node takes `invalidInput`. So
does a **Note** over 500 characters, or a **Reason** that is not numeric.

| Exit      | When                     |
| --------- | ------------------------ |
| `default` | The outage was reported. |

Variable: `<prefix>_reported`, set to `true`. If Meridian rejects the report, the node takes
`fallback`.

### Check Meridian Arrangement

Asks whether an account can set up a payment arrangement.

| Field               | What it does                                  |
| ------------------- | --------------------------------------------- |
| **Account Number**  | The account to check. Supports `$(variable)`. |
| **Variable Prefix** | Prefix for the result variable.               |

| Exit          | When                                          |
| ------------- | --------------------------------------------- |
| `eligible`    | The account can set up a payment arrangement. |
| `notEligible` | It cannot.                                    |

Variable: `<prefix>_eligible`, `true` or `false`.

## AI agent tool

An AI agent can call Meridian directly. On the agent's **Custom Tools** row, add a tool, pick
**Integration** as the kind, and choose your Meridian integration from the target list, where
it appears under a **Meridian** heading. Then set:

- **Action**, one of the five below.
- **Name** and **Description**, which tell the model what the tool is and when to use it.
- **Require caller verification**, on by default.

There is no method, path, or parameter list. The action decides what the model may send.

| Action                            | What the model supplies                                 | What comes back                                                                                                           |
| --------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| **Find Account**                  | `searchBy`, and `value`, or `zip` and `streetNumber`    | `count` and up to 10 accounts, each with `accountNumber`, `accountType`, `accountStatus`, `serviceStreet`, `serviceCity`. |
| **Get Account**                   | `accountNumber`, optionally `paymentAmount`             | The account fields listed under Get Meridian Account, with `convenienceFee` only when a `paymentAmount` was quoted.       |
| **Get Outages**                   | `accountNumber`                                         | `count` and the active outages.                                                                                           |
| **Report Outage**                 | `accountNumber`, optionally `note` and `shouldCallback` | `reported: true`.                                                                                                         |
| **Check Arrangement Eligibility** | `accountNumber`                                         | `eligible`.                                                                                                               |

Find Account returns less than the Find Meridian Account node: no names, member numbers, or
status flags. A phone search can match several households, and the model can ask which address
without reading out anyone else's details. With **Require caller verification** on, only a phone
search on the number the caller is calling from returns the addresses. Every other search
(account, member, or meter number, address, or a phone number the model supplies that is not the
caller's) returns `count` and each account's `accountNumber` only. The tool's description tells
the model so.

A callback on Report Outage goes to the number the caller is calling from. The model cannot
supply a number. In a chat there is no caller number, so a callback request comes back as an
error and the model reports the outage without one.

### Caller verification

With **Require caller verification** on, every action except Find Account is refused until the
caller has been verified for that account in the same conversation. The refusal comes back to
the model as `Verify the caller for this account before using this tool.` A verification is
kept for the rest of the conversation, including later turns, but only for the account it was
recorded for and only for the Meridian integration it was recorded against.

Find Account is never refused. With the switch on, it returns account numbers only unless it
searched by the caller's own number.

<Callout type="warn">
    **Nothing verifies callers yet.** There is no action or node that records a verification, so a
    tool with **Require caller verification** on can only find accounts. Get Account, Get Outages,
    Report Outage, and Check Arrangement Eligibility are refused every time. To use them now, turn
    the switch off for that tool. Then the model can read balances and report outages for any
    account number it is given, so do that only where your own prompt and workflow establish who the
    caller is.
</Callout>

Account details come back to the model, so write the tool's **Description** and the agent's
instructions to say what it may read out. See
[Add an integration tool](/docs/agents/voice-agents/tools#add-an-integration-tool) for how
tools are added.

## Taking a payment

A workflow takes a card payment against a Meridian account with the **Capture Payment
Information** node. The caller keys the card on the phone keypad, and Tandem charges it through
Meridian's payment gateway. The card number, expiry, and security code never reach the workflow,
its variables, or the transcript. An AI agent cannot take a payment itself: hand the call to a
workflow that contains the node. Recording, the keypad entry, and the prompts work as described
for [Authorize.net](/docs/workflows/integrations/authorize-net#taking-a-payment).

### Set up Meridian Payments

Meridian Payments is its own integration, separate from **Meridian** above. It appears in **Add
Integration** only when Meridian is on for your organization. Fill in the same details Meridian
issued for the accounts integration:

| Field                       | What to enter                                                                                                   |
| --------------------------- | --------------------------------------------------------------------------------------------------------------- |
| **Name**                    | A label for this connection, such as `Co-op payments (production)`.                                             |
| **Description**             | Optional.                                                                                                       |
| **Environment**             | **Sandbox** or **Production**. Defaults to **Sandbox**.                                                         |
| **Accounts API URL**        | The `https://` address of the Consumer Accounts API.                                                            |
| **Payment gateway URL**     | The `https://` address of the payment gateway.                                                                  |
| **Client ID**               | From Meridian.                                                                                                  |
| **Application ID**          | From Meridian.                                                                                                  |
| **Credit card merchant ID** | Optional. Digits only.                                                                                          |
| **Bank number**             | Optional. Digits only.                                                                                          |
| **API token**               | The token from Meridian. A leading `Bearer ` or `LT:` is removed for you. Enter it again when you change a URL. |

Tandem uses the token to look up the account's payment token at the moment of each charge, then
posts the sale to the payment gateway. Saving does not contact Meridian, so the first charge is
the first test. Use a **Sandbox** integration first.

### Configure the node

Add a **Capture Payment Information** node and pick your Meridian Payments integration under
**Payment Integration**. Meridian needs four things the node otherwise treats as optional:

- **Transaction Type** must be `authCapture`. Meridian takes a sale only.
- **Customer Account Number**: the member account to apply the payment to, digits only, up to 19.
  It can be a `$(variable)`, such as the account number from Find Meridian Account.
- **Convenience Fee**: a decimal such as `2.50`, with no currency symbol. It can be a
  `$(variable)`.
- **Capture CVV** and **Capture Billing ZIP** must both be on, each with its prompt. Meridian
  requires the security code and the billing ZIP on every charge.

**Amount** is the bill amount, a decimal such as `10.00`. **Name on Card** is optional, up to 50
characters. **Invoice Reference** and **Description** are not sent to Meridian.

If any of these is missing, the node takes `fallback` before the caller is asked for anything,
and the message names the problem: `Meridian requires the billing ZIP; turn on Capture Billing
ZIP`, `Meridian requires the CVV; turn on Capture CVV`, `Meridian requires the customer account
number (up to 19 digits)`, `Meridian requires the convenience fee as a decimal amount`, or
`Meridian supports sale only; set Transaction Type to authCapture`.

### Tell the caller the fee first

Tandem sends the **Convenience Fee** to Meridian as a separate amount. It does not calculate
the fee and does not play it. Get the fee from [Get Meridian Account](#get-meridian-account):
set its **Payment Amount**, read `<prefix>_convenienceFee`, play it to the caller, and ask them
to agree before the **Capture Payment Information** node. Pass the same value into **Convenience
Fee**.

### Result variables and exits

The node writes the same variables and takes the same exits as the Authorize.net node. See
[its result variables](/docs/workflows/integrations/authorize-net#result-variables). With a
prefix of `pay`, the Meridian values are:

| Variable             | Value                                                                        |
| -------------------- | ---------------------------------------------------------------------------- |
| `pay_result`         | `approved`, `declined`, `invalidInput`, or `error`.                          |
| `pay_transId`        | Meridian's tracking ID for the payment.                                      |
| `pay_authCode`       | The authorization code.                                                      |
| `pay_last4`          | The last four digits of the card.                                            |
| `pay_brand`          | The card type Meridian reports, or the type Tandem detected from the number. |
| `pay_message`        | Meridian's status message, or Tandem's when the charge failed.               |
| `pay_outcomeUnknown` | `true` when the card may have been charged despite an `error` result.        |

`pay_avsResult` is empty for Meridian. The profile variables are empty too, because Meridian
does not store the card.

| Exit           | When                                                                                                                                                   |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `default`      | Meridian approved the payment.                                                                                                                         |
| `declined`     | Meridian declined it, the account was not found (`Meridian account not found`), or the account cannot pay by card (`This account cannot pay by card`). |
| `invalidInput` | The caller did not key a complete entry, or Meridian rejected what the caller keyed, such as the card number, expiry, security code, or ZIP.           |
| `fallback`     | Anything else, including a charge whose outcome is unknown.                                                                                            |

### When the outcome is unknown

If a sale times out, the connection drops, or Meridian answers with a server error or a response
Tandem cannot read, Tandem sends the sale again, up to three times in all and within 25 seconds,
under the same reference ID, so a repeat of the same sale is recognizable to Meridian. If it
still has no answer, `pay_outcomeUnknown` is `true`, `pay_result` is `error`, and
`pay_message` is one of the messages below. The same applies when Meridian rejects the sale
after one of those attempts, a decline included: the rejection may be about the earlier
attempt's own charge, so Tandem cannot tell whether the card was charged.

- `Gateway timed out; the charge may have been captured`
- `Gateway connection dropped; the charge may have been captured`
- `Gateway response unreadable; the charge may have been captured`
- `Gateway server error; the charge may have been captured`

<Callout type="warn">
    Do not charge the card again from `fallback` when `pay_outcomeUnknown` is `true`. The first
    charge may have gone through. Check the payment with Meridian first.
</Callout>

### Payment errors

| What you see in `_message`                                         | What it means                                                                                                                                                                          |
| ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Meridian payments are not enabled in this environment`            | Card payments through Meridian are not turned on here yet. Contact Tandem support.                                                                                                     |
| `The Meridian gateway host is not on this environment's allowlist` | The **Payment gateway URL** is not one Tandem is allowed to send charges to. Contact Tandem support.                                                                                   |
| `Meridian account lookup failed`                                   | The account lookup did not succeed. Check the **Accounts API URL** and the token.                                                                                                      |
| `Meridian returned no payment token for this account`              | Meridian has no payment token for the account, so it cannot take a card payment.                                                                                                       |
| `Meridian rejected the payment token`                              | Meridian refused the account's payment token, and either a fresh one was refused too or too little of the 25 seconds was left to fetch a fresh one and send the sale again.            |
| `Meridian refused the payment token for this account`              | Meridian answered `403` for this account.                                                                                                                                              |
| `Gateway request failed`                                           | The sale could not be sent. On the first attempt nothing was charged. After an earlier attempt that may have charged, the result is one of the unknown-outcome messages above instead. |
| `Payment declined`                                                 | Meridian declined the payment and gave no message. The node takes `declined`.                                                                                                          |
| `The gateway rejected the card details`                            | Meridian rejected what the caller keyed and gave no message. The node takes `invalidInput`.                                                                                            |
| Meridian's own error message, or `Meridian rejected the sale`      | Meridian rejected the sale for a reason Tandem does not classify, and gave no message in the second case.                                                                              |

## Troubleshooting

| What you see                                                                     | What it means                                                                                                                                                    |
| -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Meridian rejected the saved credentials. Update them on the Integrations page.` | A node took `fallback` because Meridian answered `401` or `403`. The token expired or was revoked. Enter a new one.                                              |
| `Could not reach Meridian`                                                       | A node took `fallback` because the request failed. Check Meridian's status and the URLs, and that Meridian has allowlisted Tandem's addresses.                   |
| `Requests to private/internal addresses are not allowed`                         | A URL resolves to a private network. A node takes `fallback` with this message. Use the public address Meridian gave you.                                        |
| `Meridian does not have that record`                                             | No account has that number. Find Meridian Account and Get Meridian Account take `notFound`. The other nodes take `fallback` with `Meridian found no match: ...`. |
| Find Meridian Account takes `multiple`                                           | The search matched several accounts. Ask the caller which one, then search again by account number.                                                              |
| `Verify the caller for this account before using this tool.`                     | The agent tool has **Require caller verification** on, and no verification exists. See [Caller verification](#caller-verification).                              |
| A node takes `invalidInput` with `Account Number must be 1 to 19 digits`         | The value had something other than digits, spaces, and dashes, or more than 19 digits.                                                                           |
| A tool reports `accountNumber must be 1 to 19 digits`                            | The model passed something other than an account number. Say in the description that it takes digits only.                                                       |
| Adding the integration is refused as forbidden                                   | The integration is not turned on for this environment yet.                                                                                                       |
