NAV
Shell PHP Go

Juice Standard Vending API

The Juice vending API uses a set of REST API standards. These standards have the following tenants:

All API’s are:

The actual URL, Login, and Password will vary per Juice systems, for all examples a generic version such as: https://login:password@acme.utiliflex.com/acme/vending3.php is used.

Versioning

This document applies only to version 3 of the standard Juice vending API. For documentation on the previous version of this API, see the Juice Vending v2 API documentation.

Handling Authentication to the API

Authentication Checking (Basic Auth)

curl --basic --user 'login:password' --data 'mode=authtest' \
--url 'https://acme.utiliflex.com/acme/vending3.php'
<?php

$url = 'https://acme.utiliflex.com/acme/vending3.php';

$chx = curl_init();
curl_setopt($chx, CURLOPT_USERPWD, 'login:password');
curl_setopt($chx, CURLOPT_URL, $url . '?mode=authtest');
curl_setopt($chx, CURLOPT_RETURNTRANSFER, true);
curl_setopt($chx, CURLOPT_TIMEOUT, 10);
echo curl_exec($chx);
curl_close($chx);
package main

import (
  "fmt"
  "io/ioutil"
  "log"
  "net/http"
)

func main() {
  client := &http.Client{}
  req, err := http.NewRequest(http.MethodGet, "https://acme.utiliflex.com/acme/vending3.php", nil)
  if err != nil {
    log.Fatal(err)
  }

  req.SetBasicAuth("login", "password")
  q := req.URL.Query()
  q.Set("mode", "authtest")
  req.URL.RawQuery = q.Encode()
  resp, err := client.Do(req)
  defer resp.Body.Close()

  json, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    log.Fatal(err)
  }
  fmt.Printf("%s", json)
}
{
  "status": "OK",
  "error": 0,
  "message": "auth test and info",
  "vendor": {
    "vendor_number": "CEC",
    "vendor_name": "County Electric",
    "vendor_group_owed": 9477.4,
    "vendor_group_limit": 100000000,
    "vendor_group_available": 99990522.6,
    "vendor_limit": 50,
    "vendor_owed": 0,
    "vendor_available": 50
  },
  "login": "jsmith",
  "name": "John Smith",
  "email": "",
  "sms1": "",
  "system_role": "CSR3",
  "seclevel": "65"
}

Basic authentication sends the username and password as a Base64 encoded string in the HTTP headers, and is generally supported by most if not all tools and frameworks natively.

HTTP Request

GET vending3.php?mode=authtest

Available Parameters

The following URL parameters are available when preforming an authorization test:

Param Value Required Default
mode authtest Yes
return json, xml No json

Authentication checking (OAuth)

curl --header 'Authorization token jsmith:56d2bf16-9881-4e5d-bbeb-c79a72225a5b' \
--data 'mode=authtest' \
--url 'https://acme.utiliflex.com/acme/vending3.php'
<?php

$url = 'https://acme.utiliflex.com/acme/vending3.php';

$chx = curl_init();
curl_setopt($chx, CURLOPT_HTTPHEADER, array(
  'Authorization: token jsmith:56d2bf16-9881-4e5d-bbeb-c79a72225a5b',
));
curl_setopt($chx, CURLOPT_URL, $url . '?mode=authtest');
curl_setopt($chx, CURLOPT_RETURNTRANSFER, true);
curl_setopt($chx, CURLOPT_TIMEOUT, 10);
echo curl_exec($chx);
curl_close($chx);
package main

import (
  "fmt"
  "io/ioutil"
  "log"
  "net/http"
)

func main() {
  client := &http.Client{}
  req, err := http.NewRequest(http.MethodGet, "https://acme.utiliflex.com/acme/vending3.php", nil)
  if err != nil {
    log.Fatal(err)
  }

  req.Header.Add(`Authorization`, `token jsmith:56d2bf16-9881-4e5d-bbeb-c79a72225a5b`)
  q := req.URL.Query()
  q.Set("mode", "authtest")
  req.URL.RawQuery = q.Encode()
  resp, err := client.Do(req)
  if err != nil {
    log.Fatal(err)
  }
  defer resp.Body.Close()

  json, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    log.Fatal(err)
  }
  fmt.Printf("%s", json)
}
{
    "email": "",
    "error": 0,
    "login": "jsmith",
    "message": "auth test and info",
    "name": "John Smith",
    "seclevel": "65",
    "sms1": "",
    "status": "OK",
    "system_role": "CSR3",
    "vendor": {
        "vendor_available": 50,
        "vendor_group_available": 999989770.65,
        "vendor_group_limit": 1000000000,
        "vendor_group_owed": 10229.35,
        "vendor_limit": 50,
        "vendor_name": "County Electric",
        "vendor_number": "CEC",
        "vendor_owed": 0
    }
}

Using an API token the username and the API token must be in the Authorization header field in the form of token USERNAME:TOKEN for the system to recognize the token and attempt to validate it.

HTTP Request

Authorization token USERNAME:TOKEN

GET vending3.php?mode=authtest

Available Parameters

The following URL parameters are available when preforming an authorization test:

Param Value Required Default
mode authtest Yes
return json, xml No json

Account Search

curl --basic --user 'login:password' --data 'mode=search&searchfor=c2da6e3e' \
--url 'https://acme.utiliflex.com/acme/vending3.php'
<?php

$url = 'https://acme.utiliflex.com/acme/vending3.php';

$chx = curl_init();
curl_setopt($chx, CURLOPT_USERPWD, 'login:password');
curl_setopt($chx, CURLOPT_URL, $url . '?mode=search&searchfor=c2da6e3e');
curl_setopt($chx, CURLOPT_RETURNTRANSFER, true);
curl_setopt($chx, CURLOPT_TIMEOUT, 10);
echo curl_exec($chx);
curl_close($chx);
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

func main() {
	client := &http.Client{}
	req, err := http.NewRequest(http.MethodGet, "https://acme.utiliflex.com/acme/vending3.php", nil)
	if err != nil {
		log.Fatal(err)
	}

	req.SetBasicAuth("login", "password")
	q := req.URL.Query()
	q.Set("mode", "search")
	q.Set("searchfor", "c2da6e3e")
	req.URL.RawQuery = q.Encode()
	resp, err := client.Do(req)
	defer resp.Body.Close()

	json, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s", json)
}
{
  "status": "OK",
  "error": 0,
  "message": "",
  "vendor": {
    "vendor_number": "CEC",
    "vendor_name": "County Electric",
    "vendor_group_owed": 9477.4,
    "vendor_group_limit": 100000000,
    "vendor_group_available": 99990522.6,
    "vendor_limit": 50,
    "vendor_owed": 0,
    "vendor_available": 50
  },
  "login": "jsmith",
  "name": "John Smith",
  "email": "",
  "sms1": "",
  "system_role": "CSR3",
  "seclevel": "65",
  "search_results": [
    {
      "portal": "test",
      "account": "03288",
      "contract": "5004001",
      "name": "John Lennon",
      "serialnumber": "c2da6e3e",
      "address1": "123 Foo St.",
      "address2": "",
      "city": "Chattanooga",
      "state": "TN",
      "sms1": "14235551001",
      "email1": "jlennon@example.com"
    }
  ]
}

Search for an active customer account in Juice, searchable information includes:

It is suggested to use this search function to get an exact account number or meter serial number and use it for a balance check and then a vend when doing user interfaces for vendors and cashiers.

HTTP Request

GET vending3.php?mode=search&searchfor=<string>

Available Parameters

The following URL parameters are available when preforming an account search:

Param Value Required Default
mode search Yes
searchfor A string to search on Yes
return json, xml No json

Balance Inquiry

curl --basic --user 'login:password' --data 'mode=balance&account=03288' \
--url 'https://acme.utiliflex.com/acme/vending3.php'
<?php

$url = 'https://acme.utiliflex.com/acme/vending3.php';

$chx = curl_init();
curl_setopt($chx, CURLOPT_USERPWD, 'login:password');
curl_setopt($chx, CURLOPT_URL, $url . '?mode=balance&account=03288');
curl_setopt($chx, CURLOPT_RETURNTRANSFER, true);
curl_setopt($chx, CURLOPT_TIMEOUT, 10);
echo curl_exec($chx);
curl_close($chx);
package main

import (
  "fmt"
  "io/ioutil"
  "log"
  "net/http"
)

func main() {
  client := &http.Client{}
  req, err := http.NewRequest(http.MethodGet, "https://acme.utiliflex.com/acme/vending3.php", nil)
  if err != nil {
    log.Fatal(err)
  }

  req.SetBasicAuth("login", "password")
  q := req.URL.Query()
  q.Set("mode", "balance")
  q.Set("account", "03288")
  req.URL.RawQuery = q.Encode()
  resp, err := client.Do(req)
  defer resp.Body.Close()

  json, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    log.Fatal(err)
  }
  fmt.Printf("%s", json)
}
{
  "status": "OK",
  "error": 0,
  "message": "",
  "customer": {
    "account": "03288",
    "portal": "test",
    "serialnumber": "c2da6e3e",
    "locid": "L03293",
    "com": "none",
    "meterunits": "kWh",
    "meterstate": "CONNECTED",
    "vendable": 1,
    "contract": "5004001",
    "name": "John Lennon",
    "group1": "",
    "group2": "",
    "group3": "",
    "address1": "123 Foo St.",
    "address2": "",
    "notify_days": 3,
    "phone1": "14235551001",
    "phone2": "",
    "phone_notify": 0,
    "sms1": "14235551001",
    "sms2": "",
    "sms_notify": 1,
    "email1": "jlennon@example.com",
    "email2": "",
    "email_notify": 0,
    "city": "Chattanooga",
    "postal_code": "",
    "country_code": null,
    "account_type": "PrePaid",
    "loc_address1": "123 Foo St.",
    "loc_address2": "",
    "loc_city": "Chattanooga",
    "loc_name": "1009002",
    "loc_state": "TN",
    "loc_zip": "55555",
    "loc_lat": 0,
    "loc_long": 0,
    "wallet": 0,
    "gimme5_bal": 0,
    "gimme5_count": 0,
    "purchased_kwh_this_month": 0,
    "unitwallet": 27.99,
    "arrears_balance": 0
  },
  "vendor": {
    "vendor_number": "CEC",
    "vendor_name": "County Electric",
    "vendor_group_owed": 9477.4,
    "vendor_group_limit": 100000000,
    "vendor_group_available": 99990522.6,
    "vendor_limit": 50,
    "vendor_owed": 0,
    "vendor_available": 50
  },
  "login": "jsmith",
  "name": "John Smith",
  "email": "",
  "sms1": "",
  "system_role": "CSR3",
  "seclevel": "65",
  "motd": "",
  "transactions": [
    {
      "transaction": 375,
      "timestamp": "1568315822",
      "login": "jsmith",
      "serialnumber": "c2da6e3e",
      "type": "cash",
      "created": "2019-09-12 15:17:02",
      "due": "",
      "ststoken": "",
      "arrears": 0,
      "services": 10,
      "amount": 0,
      "units": 27.988,
      "unit": "kWh",
      "govnum": "0",
      "vendornumber": "CEC"
    }
  ],
  "readings": [],
  "balance": {
    "currency_wallet": 0,
    "unit_wallet": 27.99
  }
}

Preforming a balance check on an account number or a meter serial number is a way to verify if the account or meter exists within Juice. This endpoint will return all transactions for the account within the last 180 days, the last 6 meter reads depending on the type of meter the customer has, and the current currency and unit wallet balance for the account.

HTTP Request

By Account

GET vending3.php?mode=balance&account=<string>

By Meter Serial Number

GET vending3.php?mode=balance&serialnumber=<string>

Available Parameters

The following URL parameters are available when preforming a balance inquiry

Param Value Required Default
mode balance Yes
account Juice Account number to query balance for No
serialnumber Meter serial number to query balance for No
return json, xml No json

Wallet Transfer

curl --basic --user 'login:password' --data 'mode=wallettransfer&account=03288&towallet=03280&amount=10' \
--url 'https://acme.utiliflex.com/acme/vending3.php'
<?php

$url = 'https://acme.utiliflex.com/acme/vending3.php';

$chx = curl_init();
curl_setopt($chx, CURLOPT_USERPWD, 'login:password');
curl_setopt($chx, CURLOPT_URL, $url . '?mode=wallettransfer&account=03288&towallet=03280&amount=10');
curl_setopt($chx, CURLOPT_RETURNTRANSFER, true);
curl_setopt($chx, CURLOPT_TIMEOUT, 10);
echo curl_exec($chx);
curl_close($chx);
package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

func main() {
    client := &http.Client{}
    req, err := http.NewRequest(http.MethodGet, "https://acme.utiliflex.com/acme/vending3.php", nil)
    if err != nil {
        log.Fatal(err)
    }

    req.SetBasicAuth("login", "password")
    q := req.URL.Query()
    q.Set("mode", "wallettransfer")
    q.Set("account", "03288")
    q.Set("towallet", "03280")
    q.Set("amount", "10")
    req.URL.RawQuery = q.Encode()
    resp, err := client.Do(req)
    defer resp.Body.Close()

    json, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s", json)
}
{
  "status": "OK",
  "error": 0,
  "message": "transfered 10 to 03280 Ringo Starr",
  "customer": {
    "account": "03288"
  },
  "vendor": {
    "vendor_number": "CEC",
    "vendor_name": "County Electric",
    "vendor_group_owed": 9497.4,
    "vendor_group_limit": 100000000,
    "vendor_group_available": 99990502.6,
    "vendor_limit": 50,
    "vendor_owed": 20,
    "vendor_available": 30
  },
  "login": "jsmith",
  "name": "John Smith",
  "email": "",
  "sms1": "",
  "system_role": "CSR3",
  "seclevel": "65",
  "wallet_transfer": {
    "from_account": "03288",
    "to_account": "03280",
    "to_account_name": "Ringo Starr",
    "amount": 10
  }
}

It is possible for a customer to transfer money from their currency wallet in Juice to another Juice account.

HTTP Request

GET vending3.php?mode=wallettransfer&account=<string>&towallet=<string>&amount=<string>

Available Parameters

The following URL parameters are available when performing a wallet transfer

Param Value Required Default
mode wallettransfer Yes
account Juice account that the funds are transfered from Yes
towallet Juice account that the funds are transfered to Yes
amount The amount to be transfered between accounts Yes
return json, xml No json

Vending

The process of vending or funding a customer’s currency wallet is a multi-step process. The first step is getting a unique transaction ID from Juice, the second step is calling the API with either mode=vend or mode=fund using the transaction ID as a parameter in the request. The transaction ID is a unique value and can only be used once in a vend or fund request and is only valid for a max of 1 hour after it is generated. Estimate requests are an exception and the same transaction ID can be used for an estimate followed by a vend or fund action.

Vending Type Details

Cash

Setting the submode to cash is the typical use, as it is cash owed to the utility. There is no problem in Juice if the actual transaction is a credit card, check, etc.

cc

Setting the submode to cc (note the lower case) is an “outside of Juice” credit card transaction. The internal designation is cash-CC as it is a cash transaction from an external credit card gateway. The additional fields ccauth and cctrans can be used to store some corresponding transaction information in Juice to make it easier to reconcile issues and credit card statements later.

CC

Setting the submode to CC (note upper case) expects the raw credit card information fields to be passed. These fields are ccnum, ccexpmth, ccexpyr, ccfirst, cclast, cczip. This mode will accept that credit card information and process it internally to Juice.

check

Setting the submode to check denotes that the transaction amount was paid by a check, internally these transactions are handled as cash owed to the utility, but with an internal designation of cash-Check similarly to how cc transactions are handled.

Arrears

Setting the submode to arrears denotes that the transaction is an arrears transaction. While there is no money exchanging hands upfront for this type of transaction, the customer is obligated to payback the full transaction amount to the utility in future transactions.

Gimme 5

Setting the submode to gimme5 will perform a special type of arrears transaction in Juice where the system will vend a fixed amount of 5 kWh to the customer. The utility may have limitations in place on how many active Gimme 5 arrears, active being the customer is still paying back the owed balance of previous gimme5, a customer account may have at any given time or the utility may completely dis-allow Gimme 5’s to be done at all.

jc

Setting the submode to jc will perform a Juice Card transaction for the account. A Juice Card is a prepaid scratch-off card, voucher/coupon, gift card that has a fixed denomination that is it valid for. The voucher/coupon code can be purchased by the customer either at the time of the transaction or a head of time by the customer.

wallet

Setting the submode to wallet will perform a wallet transaction. During a wallet transaction there is no money exchanging hands, instead the transaction amount is withdrawn from the customer’s currency wallet as long as there is enough funds for the transaction amount.

Requesting a Transaction ID

curl --basic --user 'login:password' --data 'mode=new-transaction&account=03288' \
--url 'https://acme.utiliflex.com/acme/vending3.php'
<?php

$url = 'https://acme.utiliflex.com/acme/vending3.php';

$chx = curl_init();
curl_setopt($chx, CURLOPT_USERPWD, 'login:password');
curl_setopt($chx, CURLOPT_URL, $url . '?mode=new-transaction&account=03288');
curl_setopt($chx, CURLOPT_RETURNTRANSFER, true);
curl_setopt($chx, CURLOPT_TIMEOUT, 10);
echo curl_exec($chx);
curl_close($chx);
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

func main() {
	client := &http.Client{}
	req, err := http.NewRequest(http.MethodGet, "https://acme.utiliflex.com/acme/vending3.php", nil)
	if err != nil {
		log.Fatal(err)
	}

	req.SetBasicAuth("login", "password")
	q := req.URL.Query()
	q.Set("mode", "new-transaction")
	q.Set("account", "03288")
	req.URL.RawQuery = q.Encode()
	resp, err := client.Do(req)
	defer resp.Body.Close()

	json, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s", json)
}
{
  "status": "OK",
  "error": 0,
  "message": "",
  "customer": {
    "account": "03288"
  },
  "vendor": {
    "vendor_number": "CEC",
    "vendor_name": "County Electric",
    "vendor_group_owed": 9477.4,
    "vendor_group_limit": 100000000,
    "vendor_group_available": 99990522.6,
    "vendor_limit": 50,
    "vendor_owed": 0,
    "vendor_available": 50
  },
  "login": "jsmith",
  "name": "John Smith",
  "email": "",
  "sms1": "",
  "system_role": "CSR3",
  "seclevel": "65",
  "transaction": {
    "uuid": "af8d5fb2-0a3d-11ea-a672-df1c41ad4042"
  }
}

In order to be able to perform either a vend or fund action a unique transaction ID must be generated. This transaction ID is tied to the vendor account, customer account, and the transaction that is performed. The generated transaction ID will be the uuid field in the transaction object.

HTTP Request

GET vending3.php?mode=new-transaction&account=<string>

Available Parameters

The following URL parameters are available when getting a transaction ID:

Param Value Required Default
mode new-transaction Yes
account Juice account number that the transaction is for Yes
return json, xml No json

Sales Estimate

curl --basic --user 'login:password' --data 'mode=estimate&submode=cash&account=03288&amount=10&uuid=af8d5fb2-0a3d-11ea-a672-df1c41ad4042' \
--url 'https://acme.utiliflex.com/acme/vending3.php'
<?php

$url = 'https://acme.utiliflex.com/acme/vending3.php';

$chx = curl_init();
curl_setopt($chx, CURLOPT_USERPWD, 'login:password');
curl_setopt($chx, CURLOPT_URL, $url . '?mode=estimate&submode=cash&account=03288&amount=10&uuid=af8d5fb2-0a3d-11ea-a672-df1c41ad4042');
curl_setopt($chx, CURLOPT_RETURNTRANSFER, true);
curl_setopt($chx, CURLOPT_TIMEOUT, 10);
echo curl_exec($chx);
curl_close($chx);
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

func main() {
	client := &http.Client{}
	req, err := http.NewRequest(http.MethodGet, "https://acme.utiliflex.com/acme/vending3.php", nil)
	if err != nil {
		log.Fatal(err)
	}

	req.SetBasicAuth("login", "password")
	q := req.URL.Query()
	q.Set("mode", "estimate")
	q.Set("submode", "cash")
	q.Set("account", "03288")
	q.Set("amount", "10")
	q.Set("uuid", "af8d5fb2-0a3d-11ea-a672-df1c41ad4042")
	req.URL.RawQuery = q.Encode()
	resp, err := client.Do(req)
	defer resp.Body.Close()

	json, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s", json)
}
{
  "uuid": "af8d5fb2-0a3d-11ea-a672-df1c41ad4042",
  "status": "OK",
  "error": 0,
  "message": "",
  "customer": {
    "account": "03288",
    "portal": "test",
    "serialnumber": "c2da6e3e",
    "locid": "L03293",
    "com": "none",
    "meterunits": "kWh",
    "meterstate": "CONNECTED",
    "vendable": 1,
    "contract": "5004001",
    "name": "John Lennon",
    "group1": "",
    "group2": "",
    "group3": "",
    "address1": "123 Foo St.",
    "address2": "",
    "notify_days": 3,
    "phone1": "14235551001",
    "phone2": "",
    "phone_notify": 0,
    "sms1": "14235551001",
    "sms2": "",
    "sms_notify": 1,
    "email1": "jlennon@example.com",
    "email2": "",
    "email_notify": 0,
    "city": "Chattanooga",
    "postal_code": "",
    "country_code": null,
    "account_type": "PrePaid",
    "loc_address1": "123 Foo St.",
    "loc_address2": "",
    "loc_city": "Chattanooga",
    "loc_name": "1009002",
    "loc_state": "TN",
    "loc_zip": "55555",
    "loc_lat": 0,
    "loc_long": 0,
    "wallet": 0,
    "gimme5_bal": 0,
    "gimme5_count": 0,
    "purchased_kwh_this_month": 0,
    "unitwallet": 27.99,
    "arrears_balance": 0
  },
  "vendor": {
    "vendor_number": "CEC",
    "vendor_name": "County Electric",
    "vendor_group_owed": 9477.4,
    "vendor_group_limit": 100000000,
    "vendor_group_available": 99990522.6,
    "vendor_limit": 50,
    "vendor_owed": 0,
    "vendor_available": 50
  },
  "login": "jsmith",
  "name": "John Smith",
  "email": "",
  "sms1": "",
  "system_role": "CSR3",
  "seclevel": "65",
  "motd": "",
  "transaction": {
    "id": 0,
    "action": "ESTIMATE",
    "amount": 10,
    "apply_to_arrears": 0,
    "apply_to_fixed": 0,
    "apply_to_services": 10,
    "apply_to_taxes": 0,
    "apply_to_fuel_charges": 0,
    "apply_to_levy_charges": 0,
    "apply_to_levy2_charges": 0,
    "apply_to_wallet": 0,
    "purchased_kwh": 27.9877,
    "kva_demand_charge": 0,
    "bt1amt": 10,
    "bt2amt": 0,
    "bt3amt": 0,
    "bt4amt": 0,
    "bt5amt": 0,
    "bt6amt": 0,
    "bt7amt": 0,
    "bt8amt": 0,
    "bt9amt": 0,
    "bt1wh": 27987.7,
    "bt2wh": 0,
    "bt3wh": 0,
    "bt4wh": 0,
    "bt5wh": 0,
    "bt6wh": 0,
    "bt7wh": 0,
    "bt8wh": 0,
    "bt9wh": 0
  }
}

A sales estimate can be done to test a transaction without making a sale. This is useful to see what the break down of the transaction should be including the amount of units that will be purchased by the customer, and how much of the transaction amount will be used to pay down any outstanding arrears. This will also allows the vendor to check to see if the transaction would put them over their allowed vending limit or not.

HTTP Request

Sales estimate with account number

GET vending3.php?mode=estimate&submode=<string>&account=<string>&amount=<number>&uuid=<string>

Sales estimate with meter serial number

GET vending3.php?mode=estimate&submode=<string>&serialnumber=<string>&amount=<number>&uuid=<string>

Available Parameters

The following URL parameters are available when performing a sales estimate

Param Value Required Default
mode estimate Yes
submode cash, cc, CC, check, arrears, gimme5, jc, wallet Yes
account Juice account that is being vended to/funded No
serialnumber Meter serial number of the account that is being vended to/funded No
amount The transaction amount Yes*1
coupon If submode=jc then this field is the unique code for the Juice Card No
ccauth If submode=cc then this field is the authorization code from the Credit Card Terminal No
cctrans If submode=cc then this field is the transaction code from the Credit Card Terminal No
ccnum If submode=CC then this is the Credit Card number to be sent to the CC gateway for processing No
ccexpnth If submode=CC then this is the expiration month of the card to be sent to the CC gateway for processing No
ccexpyr If submode=CC then this is the expiration year of the card to be sent to the CC gateway for processing No
ccfirst If submode=CC then this is the first name on the card to be sent to the CC gateway for processing No
cclast If submode=CC then this is the last name on the card to be sent to the CC gateway for processing No
cczip If submode=CC then this is the billing zip code to be sent to the CC gateway for processing No
uuid The unique transaction ID generated by Juice Yes
return json, xml No json

Sales / Vending

curl --basic --user 'login:password' --data 'mode=vend&submode=cash&account=03288&amount=10&uuid=af8d5fb2-0a3d-11ea-a672-df1c41ad4042' \
--url 'https://acme.utiliflex.com/acme/vending3.php'
<?php

$url = 'https://acme.utiliflex.com/acme/vending3.php';

$chx = curl_init();
curl_setopt($chx, CURLOPT_USERPWD, 'login:password');
curl_setopt($chx, CURLOPT_URL, $url . '?mode=vend&submode=cash&account=03288&amount=10&uuid=af8d5fb2-0a3d-11ea-a672-df1c41ad4042');
curl_setopt($chx, CURLOPT_RETURNTRANSFER, true);
curl_setopt($chx, CURLOPT_TIMEOUT, 10);
echo curl_exec($chx);
curl_close($chx);
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

func main() {
	client := &http.Client{}
	req, err := http.NewRequest(http.MethodGet, "https://acme.utiliflex.com/acme/vending3.php", nil)
	if err != nil {
		log.Fatal(err)
	}

	req.SetBasicAuth("login", "password")
	q := req.URL.Query()
	q.Set("mode", "vend")
	q.Set("submode", "cash")
	q.Set("account", "03288")
	q.Set("amount", "10")
	q.Set("uuid", "af8d5fb2-0a3d-11ea-a672-df1c41ad4042")
	req.URL.RawQuery = q.Encode()
	resp, err := client.Do(req)
	defer resp.Body.Close()

	json, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s", json)
}
{
  "uuid": "af8d5fb2-0a3d-11ea-a672-df1c41ad4042",
  "status": "OK",
  "error": 0,
  "message": "",
  "customer": {
    "account": "03288",
    "portal": "test",
    "serialnumber": "c2da6e3e",
    "locid": "L03293",
    "com": "none",
    "meterunits": "kWh",
    "meterstate": "CONNECTED",
    "vendable": 1,
    "contract": "5004001",
    "name": "John Lennon",
    "group1": "",
    "group2": "",
    "group3": "",
    "address1": "123 Foo St.",
    "address2": "",
    "notify_days": 3,
    "phone1": "14235551001",
    "phone2": "",
    "phone_notify": 0,
    "sms1": "14235551001",
    "sms2": "",
    "sms_notify": 1,
    "email1": "jlennon@example.com",
    "email2": "",
    "email_notify": 0,
    "city": "Chattanooga",
    "postal_code": "",
    "country_code": null,
    "account_type": "PrePaid",
    "loc_address1": "123 Foo St.",
    "loc_address2": "",
    "loc_city": "Chattanooga",
    "loc_name": "1009002",
    "loc_state": "TN",
    "loc_zip": "55555",
    "loc_lat": 0,
    "loc_long": 0,
    "wallet": 0,
    "gimme5_bal": 0,
    "gimme5_count": 0,
    "purchased_kwh_this_month": 0,
    "unitwallet": "27.99",
    "arrears_balance": 0
  },
  "vendor": {
    "vendor_number": "CEC",
    "vendor_name": "County Electric",
    "vendor_group_owed": 9487.4,
    "vendor_group_limit": 100000000,
    "vendor_group_available": 99990512.6,
    "vendor_limit": 50,
    "vendor_owed": 10,
    "vendor_available": 40
  },
  "login": "jsmith",
  "name": "John Smith",
  "email": "",
  "sms1": "",
  "system_role": "CSR3",
  "seclevel": "65",
  "motd": "",
  "transaction": {
    "id": 430,
    "action": "SALE",
    "type": "cash",
    "amount": 10,
    "apply_to_arrears": 0,
    "apply_to_fixed": 0,
    "apply_to_services": 10,
    "apply_to_taxes": 0,
    "apply_to_fuelcharges": 0,
    "apply_to_wallet": 0,
    "purchased_kwh": 27.99,
    "kva_demand_charge": 0,
    "bt1wh": 27988,
    "bt1amt": 10,
    "bt2wh": 0,
    "bt2amt": 0,
    "bt3wh": 0,
    "bt3amt": 0,
    "bt4wh": 0,
    "bt4amt": 0,
    "bt5wh": 0,
    "bt5amt": 0,
    "bt6wh": 0,
    "bt6amt": 0,
    "bt7wh": 0,
    "bt7amt": 0,
    "bt8wh": 0,
    "bt8amt": 0,
    "bt9wh": 0,
    "bt9amt": 0,
    "govnum": "0"
  }
}

This endpoint performs a sale to the customer account, the most common vending submode is cash as it is cash owed to the utility and the utility does not typcially accept the risks associated with other credit based payment methods by an external vendor. There are exceptions when the when the Vending API is used for tight integrations with a payment provider that acts as a front end (cashier) for the utility.

HTTP Request

Sales estimate with account number

GET vending3.php?mode=vend&submode=<string>&account=<string>&amount=<number>&uuid=<string>

Sales estimate with meter serial number

GET vending3.php?mode=vend&submode=<string>&serialnumber=<string>&amount=<number>&uuid=<string>

Available Parameters

The following URL parameters are available when performing a sales estimate

Param Value Required Default
mode vend Yes
submode cash, cc, CC, check, arrears, gimme5, jc, wallet Yes
account Juice account that is being vended to/funded No
serialnumber Meter serial number of the account that is being vended to/funded No
amount The transaction amount Yes*1
coupon If submode=jc then this field is the unique code for the Juice Card No
ccauth If submode=cc then this field is the authorization code from the Credit Card Terminal No
cctrans If submode=cc then this field is the transaction code from the Credit Card Terminal No
ccnum If submode=CC then this is the Credit Card number to be sent to the CC gateway for processing No
ccexpnth If submode=CC then this is the expiration month of the card to be sent to the CC gateway for processing No
ccexpyr If submode=CC then this is the expiration year of the card to be sent to the CC gateway for processing No
ccfirst If submode=CC then this is the first name on the card to be sent to the CC gateway for processing No
cclast If submode=CC then this is the last name on the card to be sent to the CC gateway for processing No
cczip If submode=CC then this is the billing zip code to be sent to the CC gateway for processing No
uuid The unique transaction ID generated by Juice Yes
return json, xml No json

Funding a currency wallet

curl --basic --user 'login:password' --data 'mode=fund&submode=cash&account=03288&amount=10&uuid=3743f6c0-0bb3-11ea-b926-0832e398a56c' \
--url 'https://acme.utiliflex.com/acme/vending3.php'
<?php

$url = 'https://acme.utiliflex.com/acme/vending3.php';

$chx = curl_init();
curl_setopt($chx, CURLOPT_USERPWD, 'login:password');
curl_setopt($chx, CURLOPT_URL, $url . '?mode=fund&submode=cash&account=03288&amount=10&uuid=3743f6c0-0bb3-11ea-b926-0832e398a56c');
curl_setopt($chx, CURLOPT_RETURNTRANSFER, true);
curl_setopt($chx, CURLOPT_TIMEOUT, 10);
echo curl_exec($chx);
curl_close($chx);
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

func main() {
	client := &http.Client{}
	req, err := http.NewRequest(http.MethodGet, "https://acme.utiliflex.com/acme/vending3.php", nil)
	if err != nil {
		log.Fatal(err)
	}

	req.SetBasicAuth("login", "password")
	q := req.URL.Query()
	q.Set("mode", "fund")
	q.Set("submode", "cash")
	q.Set("account", "03288")
	q.Set("amount", "10")
	q.Set("uuid", "3743f6c0-0bb3-11ea-b926-0832e398a56c")
	req.URL.RawQuery = q.Encode()
	resp, err := client.Do(req)
	defer resp.Body.Close()

	json, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s", json)
}
{
  "uuid": "3743f6c0-0bb3-11ea-b926-0832e398a56c",
  "status": "OK",
  "error": 0,
  "message": "",
  "customer": {
    "account": "03288",
    "portal": "test",
    "serialnumber": "c2da6e3e",
    "locid": "L03293",
    "com": "none",
    "meterunits": "kWh",
    "meterstate": "CONNECTED",
    "vendable": 1,
    "contract": "5004001",
    "name": "John Lennon",
    "group1": "",
    "group2": "",
    "group3": "",
    "address1": "123 Foo St.",
    "address2": "",
    "notify_days": 3,
    "phone1": "14235551001",
    "phone2": "",
    "phone_notify": 0,
    "sms1": "14235551001",
    "sms2": "",
    "sms_notify": 1,
    "email1": "jlennon@example.com",
    "email2": "",
    "email_notify": 0,
    "city": "Chattanooga",
    "postal_code": "",
    "country_code": null,
    "account_type": "PrePaid",
    "loc_address1": "123 Foo St.",
    "loc_address2": "",
    "loc_city": "Chattanooga",
    "loc_name": "1009002",
    "loc_state": "TN",
    "loc_zip": "55555",
    "loc_lat": 0,
    "loc_long": 0,
    "wallet": 0,
    "gimme5_bal": 0,
    "gimme5_count": 0,
    "purchased_kwh_this_month": 28,
    "unitwallet": 27.99,
    "arrears_balance": 0
  },
  "vendor": {
    "vendor_number": "CEC",
    "vendor_name": "County Electric",
    "vendor_group_owed": 9497.4,
    "vendor_group_limit": 100000000,
    "vendor_group_available": 99990502.6,
    "vendor_limit": 50,
    "vendor_owed": 20,
    "vendor_available": 30
  },
  "login": "jsmith",
  "name": "John Smith",
  "email": "",
  "sms1": "",
  "system_role": "CSR3",
  "seclevel": "65",
  "motd": "",
  "wallet": {
    "transaction_id": 431,
    "action": "FUND",
    "fund_amount": 10,
    "balance": 10
  }
}

When funding a customer’s currency wallet, the funds will be added to their current balance for later use. Funding a wallet does not generate a transaction unless the customer has a auto vend percentage set.

HTTP Request

GET vending3.php?mode=fund&submode=<string>&account=<string>&amount=<string>&uuid=<string>

Available Parameters

The following URL parameters are available when performing a wallet fund

Param Values Required Default
mode fund Yes
submode cash, cc Yes
account Juice account that is being vended to/funded No
serialnumber Meter serial number of the account that is being vended to/funded No
amount The transaction amount Yes
ccauth If submode=cc then this field is the authorization code from the Credit Card Terminal No
cctrans If submode=cc then this field is the transaction code from the Credit Card Terminal No
uuid The unique transaction ID generated by Juice Yes
return json, xml No json

Transaction Check

curl --basic --user 'login:password' --data 'mode=vend-check&uuid=af8d5fb2-0a3d-11ea-a672-df1c41ad4042' \
--url 'https://acme.utiliflex.com/acme/vending3.php'
<?php

$url = 'https://acme.utiliflex.com/acme/vending3.php';

$chx = curl_init();
curl_setopt($chx, CURLOPT_USERPWD, 'login:password');
curl_setopt($chx, CURLOPT_URL, $url . '?mode=vend-check&uuid=af8d5fb2-0a3d-11ea-a672-df1c41ad4042');
curl_setopt($chx, CURLOPT_RETURNTRANSFER, true);
curl_setopt($chx, CURLOPT_TIMEOUT, 10);
echo curl_exec($chx);
curl_close($chx);
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

func main() {
	client := &http.Client{}
	req, err := http.NewRequest(http.MethodGet, "https://acme.utiliflex.com/acme/vending3.php", nil)
	if err != nil {
		log.Fatal(err)
	}

	req.SetBasicAuth("login", "password")
	q := req.URL.Query()
	q.Set("mode", "vend-check")
	q.Set("uuid", "af8d5fb2-0a3d-11ea-a672-df1c41ad4042")
	req.URL.RawQuery = q.Encode()
	resp, err := client.Do(req)
	defer resp.Body.Close()

	json, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s", json)
}
{
  "uuid": "af8d5fb2-0a3d-11ea-a672-df1c41ad4042",
  "status": "OK",
  "error": 0,
  "message": "",
  "vendor": {
    "vendor_number": "CEC",
    "vendor_name": "County Electric",
    "vendor_group_owed": 9497.4,
    "vendor_group_limit": 100000000,
    "vendor_group_available": 99990502.6,
    "vendor_limit": 50,
    "vendor_owed": 20,
    "vendor_available": 30
  },
  "login": "jsmith",
  "name": "John Smith",
  "email": "",
  "sms1": "",
  "system_role": "CSR3",
  "seclevel": "65",
  "transaction": {
    "id": 430,
    "type": "cash",
    "amount": 10,
    "apply_to_arrears": 0,
    "apply_to_fixed": 0,
    "apply_to_services": 10,
    "apply_to_taxes": 0,
    "apply_to_fuelcharges": 0,
    "apply_to_wallet": 0,
    "purchased_kwh": 27.99,
    "kva_demand_charge": 0,
    "bt1wh": 27988,
    "bt1amt": 10,
    "bt2wh": 0,
    "bt2amt": 0,
    "bt3wh": 0,
    "bt3amt": 0,
    "bt4wh": 0,
    "bt4amt": 0,
    "bt5wh": 0,
    "bt5amt": 0,
    "bt6wh": 0,
    "bt6amt": 0,
    "bt7wh": 0,
    "bt7amt": 0,
    "bt8wh": 0,
    "bt8amt": 0,
    "bt9wh": 0,
    "bt9amt": 0,
    "govnum": "0"
  }
}

The mode=vend-check endpoint allows returning transaction details for a specific Juice transaction ID or transaction UUID. This endpoint is useful for verifying if Juice has received and processed a previous vend request.

HTTP Request

Transaction check with Juice transaction id

GET vending3.php?mode=vend-check&transaction=<int>

Transaction check with Juice transaction UUID

GET vending3.php?mode=vend-check&uuid=<string>

Available Parameters

The URL Parameters available during a vend check are as follows:

Param Value Required Default
mode vend-check Yes
transaction The Juice transaction ID No
uuid The Juice UUID that used for the transaction No
return json, xml No json

Updating Customer Information

curl --basic --user 'login:password' --data 'mode=updatecustomer&account=03288&phone1=14235290857' \
--url 'https://acme.utiliflex.com/acme/vending3.php'
<?php

$url = 'https://acme.utiliflex.com/acme/vending3.php';

$chx = curl_init();
curl_setopt($chx, CURLOPT_USERPWD, 'login:password');
curl_setopt($chx, CURLOPT_URL, $url . '?mode=updatecustomer&account=03288&phone1=14235290857');
curl_setopt($chx, CURLOPT_RETURNTRANSFER, true);
curl_setopt($chx, CURLOPT_TIMEOUT, 10);
echo curl_exec($chx);
curl_close($chx);
package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

func main() {
    client := &http.Client{}
    req, err := http.NewRequest(http.MethodGet, "https://acme.utiliflex.com/acme/vending3.php", nil)
    if err != nil {
        log.Fatal(err)
    }

    req.SetBasicAuth("login", "password")
    q := req.URL.Query()
    q.Set("mode", "updatecustomer")
    q.Set("account", "03288")
    q.Set("phone1", "14235290857")
    req.URL.RawQuery = q.Encode()
    resp, err := client.Do(req)
    defer resp.Body.Close()

    json, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s", json)
}
{
  "status": "OK",
  "error": 0,
  "message": "account 03288 updated",
  "customer": {
    "account": "03288",
    "portal": "test",
    "serialnumber": "c2da6e3e",
    "locid": "L03293",
    "com": "none",
    "meterunits": "kWh",
    "meterstate": "CONNECTED",
    "vendable": 1,
    "contract": "5004001",
    "name": "John Lennon",
    "group1": "",
    "group2": "",
    "group3": "",
    "address1": "123 Foo St.",
    "address2": "",
    "notify_days": 3,
    "phone1": "14235290856",
    "phone2": "",
    "phone_notify": 0,
    "sms1": "14235551001",
    "sms2": "",
    "sms_notify": 1,
    "email1": "jlennon@example.com",
    "email2": "",
    "email_notify": 0,
    "city": "Chattanooga",
    "postal_code": "",
    "country_code": null,
    "account_type": "PrePaid",
    "loc_address1": "123 Foo St.",
    "loc_address2": "",
    "loc_city": "Chattanooga",
    "loc_name": "1009002",
    "loc_state": "TN",
    "loc_zip": "55555",
    "loc_lat": 0,
    "loc_long": 0,
    "wallet": 0,
    "gimme5_bal": 0,
    "gimme5_count": 0,
    "purchased_kwh_this_month": 28,
    "unitwallet": 27.99,
    "arrears_balance": 0
  },
  "vendor": {
    "vendor_number": "CEC",
    "vendor_name": "County Electric",
    "vendor_group_owed": 9497.4,
    "vendor_group_limit": 100000000,
    "vendor_group_available": 99990502.6,
    "vendor_limit": 50,
    "vendor_owed": 20,
    "vendor_available": 30
  },
  "login": "jsmith",
  "name": "John Smith",
  "email": "",
  "sms1": "",
  "system_role": "CSR3",
  "seclevel": "65",
  "motd": ""
}

It is possible to update a limited set of customer billing Information using this end point.

HTTP Request

GET vending3.php?mode=updatecustomer&account=<string>&<field>=<string>

Available Parameters

The following URL parameters are available when updating customer information:

Param Value Required Default
mode updatecustomer Yes
phone1 Updates the customer’s primary phone number No
phone2 Updates the customer’s secondary phone number No
email1 Updates the customer’s primary email address No
email2 Updates the customer’s secondary email address No
sms1 Updates the customer’s primary SMS number No
sms2 Updates the customer’s secondary SMS number No
notifydays Updates the number of days before sending a low balance notice to the customer No
emailnotify Updates if the customer should get notices via email (value should be 1 = yes 0 = no) No
smsnotify Updates if the customer should get notices via SMS (value should be 1 = yes 0 = no) No
address1 Updates the customer’s address information No
address2 Updates the customer’s address information No
city Updates the customer’s city information No
postalcode Updates the customer’s zip/postal code No
countrycode Updates the customer’s country information No
return json, xml No json

Key / Values to Submit

General Key / Values

The following key / value pairs are valid for all requests to this API:

Key Value Description/Comments
mode authtest, wallettransfer, balance, estimate, vend, fund, updatecustomer, search, new-transaction Top level action to perform, this parameter is always required
account customers Juice account number in most cases the meter serial number can be used instead
serialnumber meter serial number must be unique in this portal
lang any two character language code optional, en is default, mostly affects error messages
return xml, json

Account Search Key / Values

The following additional key / value pairs are valid for account search only: mode=search:

Key Value Description/Comments
searchfor a string to use for searching for an account in Juice. See the Account Search section for list of searchable fields

Vending / Funding Key / Values

The following additional key / value pairs are valid for vending or funding only:

Key Value Description/Comments
submode cash, cc, CC, check, arrears, gimme5, jc, wallet The transaction type for a vend/fund, certain modes limit the type of submodes that can be performed
transaction the numeric Juice transaction ID
uuid the unique UUID generated by this API to preform a vend/fund action
ccauth credit card auth string when submode=cc
cctrans credit card transaction number when submode=cc
ccnum credit card number when submode=CC
ccexpmth credit card expiration month when submode=CC
ccexpyr credit card expiration year when submode=CC
ccfirst card holders first name as it appears on the card when submode=CC
cclast card holders last name as it appears on the card when submode=CC
cczip card holders billing zip code when submode=CC
cccountry card holders country code when submode=CC
amount amount in the local/system currency
smsto send an SMS receipt (with token if applicable) to either one of the two cellphone numbers on file, or a submitted number Valid values are 1 or 2 or any valid cellphone number. This value is optional.
towallet the receiving Juice account number for a wallet transfer This parameter is only valid when doing a wallet transfer
includereceipt returns a Juice formatted receipt for a transaction if includereceipt=yes Only valid for transactions (mode=vend)

Account Update Key / Values

The following additional key / value pairs are valid for account update only:

Key Value Description/Comments
phone1/phone2 allows updating the customers phone1 or phone2 information Only valid if mode=updatecustomer
email1/email2 allows updating the customers email1 or email2 information Only valid if mode=updatecustomer
sms1/sms2 allows updating the customers sms1 or sms2 information Only valid if mode=updatecustomer
notifydays allows changing the number of days the customer should start receiving low balance notifications Only valid if mode=updatecustomer
emailnotify allows changing if the customer should get low balance notices via email Only valid if mode=updatecustomer
smsnotify allows changing if the customer should get low balance notices via SMS Only valid if mode=updatecustomer
address1/address2 allows changing the customers billing address information Only valid if mode=updatecustomer
city allows changing the customers billing city information Only valid if mode=updatecustomer
postalcode allows changing the customers billing zip/postal code Only valid if mode=updatecustomer
countrycode allows changing the customers billing country code Only valid if mode=updatecustomer

Errors

The Juice Vending API uses the following error codes:

Error Code Meaning
0 No error
1001 Could not locate a matching meter serial number or account
1002 A currency amount is required for this transaction
1003 Amount exceeds gateway single transaction limit
1004 The mode key is not set
1005 The submode is invalid or missing for the mode
1006 Invalid submode for wallet funding
1007 Duplicate POST detected, Resubmit in 2 minutes if valid
1010 Vending not allowed or other error has occurred
1011 Failed to update customer information
1080 Bad currency amount or currency type
1090 No UUID given for vend/fund action
1091 Invalid UUID given for vend/fund action
1099 Transaction Error: (text will vary according to the error, this is a non-API error)
1101 Transaction Error: Credit Card failed either validity or expiration date has failed
9999 A general error occurred while processing the request