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:
- Encrypted (https on a standard (443) or special port)
- Uses “basic authentication” as a minimum
- Uses a key=value pair request as a GET or POST
- Can return XML or JSON
- Atomic (One request per API call)
- Easy to demonstrate or debug with cURL or a web browser
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:
- Meter Serial Number
- Juice Account Number
- Legacy CIS Account Number
- Customer Name
- Customer Phone Numbers
- Customer SMS Numbers
- Customer Email Address(es)
- CIS/HeadEnd/MDM Meter ID
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 mode s 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 |