Enroll a new customer¶
Overview¶
To enroll a new customer the following steps need to take place:
-
Product Lookup: It is recommeded that you query our products using the customer's
postcode
orESI ID
to make sure we have products that will be served in the customer's area. We've a handy how-to guide available here -
Create an Account : This includes customer's address, billing information, and sales information. We use sales information to track who made this sale. It is recommended that you always make sure that each account that is created by you provides the correct
salesChannel
to get its attribution.- You can also use the
uniqueReferenceNumber
field to track a sale that you've made.
- You can also use the
-
Credit check: All postpay products do require a credit check. And based on the credit check status, we either request the customer to pay a deposit, or we request our affiliates to recommend our prepay products.
- Note: Credit check is optional if the customer agrees to pay a deposit, or legally qualifies for a waiver (will have to give us a call).
-
Add property and product: Add the address of the property and choose if the customer wants to move-in or needs a switch-request to be made. You will also have to pass the product id that customer has chosen and optionally pass a
autoTopUpPaymentAmount
that is needed for prepay products.
Example of an enrollment journey¶
The following subsections should be followed in the given order.
Create an account for a new customer¶
Authentication Required
Requires CAN_CREATE_ACCOUNTS
permission.
-
Arguments
input
: CreateAccountInputaccountUser
: AccountUserInput!billingAddress
: BillingAddressInput!salesInformation
: SalesInfoInput!
-
Returns
account
: CreateAccountOutput
Info
We recommend that our affiliates should perform credit checks on their own. But if there is a need, we can perform credit checks on behalf of them. You can pass a social security number to the create account mutation and it will do the credit check on behalf of your organization.
Note: We won't be returning the credit score back to you. And using this service requires prior approval of the management and legal team.
import datetime
import pprint
import requests
# API_URL = "https://api.oeus-kraken.energy/v1/graphql/" # prod
API_URL = "https://api.oeus-kraken.systems/v1/graphql/" # test
JWT_TOKEN = "PLACE_JWT_TOKEN_HERE"
HEADERS = {
"Authorization": f"JWT {JWT_TOKEN}"
}
def _setup_account_input(
mobile: str = "2014007000",
email: str = "JohnDoe@gmail.com",
zip_code: str = "77004",
opted_in_for_marketing: bool = True,
opted_in_to_recommended_messages: bool = True,
opted_in_to_updates: bool = True,
opted_in_to_associated_companies: bool = False,
opted_in_to_third_parties: bool = False,
opted_in_to_sms: bool = True,
state: str = "TX",
sales_affiliate_subdomain: str = None,
uniqueReferenceNumber: str = "some-unique-reference-number"
):
sales_subchannel = "SOME ORGANIZATION"
communication_preference = "ONLINE"
language_preference = "ENGLISH"
return {
"accountUser": {
"givenName": "John",
"familyName": "Doe",
"email": email,
"mobile": mobile,
"landline": "4407701608",
"communicationPreference": communication_preference,
"languagePreference": language_preference,
"dateOfBirth": datetime.date(year=1991, month=1, day=1).isoformat(),
},
"billingAddress": {
"address1": "13th Madison Avenue",
"address2": "Apartment number 207",
"city": "Austin",
"state": state,
"zipCode": zip_code,
},
"salesInformation": {
"salesSubchannel": sales_subchannel,
"salesAffiliateSubdomain": sales_affiliate_subdomain,
"optedInForMarketing": opted_in_for_marketing,
"optedInToRecommendedMessages": opted_in_to_recommended_messages,
"optedInToUpdates": opted_in_to_updates,
"optedInToAssociatedCompanies": opted_in_to_associated_companies,
"optedInToThirdParties": opted_in_to_third_parties,
"optedInToSms": opted_in_to_sms,
"uniqueReferenceNumber": uniqueReferenceNumber
},
}
QUERY = """
mutation createAccount($input:CreateAccountInput!){
createAccount(input:$input){
__typename
account{
number
__typename
}
}
}
"""
input = _setup_account_input()
VARIABLES={ "input": input }
session = requests.Session()
session.headers.update(HEADERS)
response = session.post(
url=API_URL,
json={"query": QUERY, "variables": VARIABLES}
)
pprint.pprint(response.json())
const axios = require("axios")
// const apiUrl = "https://api.oeus-kraken.energy/v1/graphql/" // Prod
const apiUrl = "https://api.oeus-kraken.systems/v1/graphql/" // Test
const jwtToken = "place_jwtToken_here"
let headers = {
"Authorization": `JWT ${jwtToken}`
}
const setupAccountInput = (
mobile = "2014007000",
email = "JohnDoe@gmail.com",
zipCode = "77004",
optedInForMarketing = true,
optedInToRecommendedMessages = true,
optedInToUpdates = true,
optedInToAssociatedCompanies = false,
optedInToThirdParties = false,
optedInToSms = true,
state = "TX",
salesAffiliateSubdomain = null
) => {
let salesSubchannel = "SOME ORGANIZATION"
let communicationPreference = "ONLINE"
let languagePreference = "ENGLISH"
return {
"accountUser": {
"givenName": "John",
"familyName": "Doe",
"email": email,
"mobile": mobile,
"landline": "4407701608",
"communicationPreference": communicationPreference,
"languagePreference": languagePreference,
"dateOfBirth": new Date("1991-01-01").toLocaleDateString('en-CA', { year: 'numeric', month: '2-digit', day: '2-digit' })
},
"billingAddress": {
"address1": "13th Madison Avenue",
"address2": "Apartment number 207",
"city": "Austin",
"state": state,
"zipCode": zipCode,
},
"salesInformation": {
"salesSubchannel": salesSubchannel,
"salesAffiliateSubdomain": salesAffiliateSubdomain,
"optedInForMarketing": optedInForMarketing,
"optedInToRecommendedMessages": optedInToRecommendedMessages,
"optedInToUpdates": optedInToUpdates,
"optedInToAssociatedCompanies": optedInToAssociatedCompanies,
"optedInToThirdParties": optedInToThirdParties,
"optedInToSms": optedInToSms,
},
}
}
const query = `
mutation createAccount($input:CreateAccountInput!){
createAccount(input:$input){
__typename
account{
number
__typename
}
}
}
`
let input = setupAccountInput()
const variables = {"input": input}
axios({
url: apiUrl,
method: "post",
data: {
query: query,
variables: variables,
},
headers: headers,
}).then((response) => {
console.log(JSON.stringify(response.data, null, 4));
});
import axios from 'axios';
// const API_URL = "https://api.oeus-kraken.energy/v1/graphql/" // Prod
export const apiUrl = "https://api.oeus-kraken.systems/v1/graphql/" // Test
export const jwtToken = "PLACE_JWT_TOKEN_HERE"
let headers = {"Authorization": `JWT ${jwtToken}`}
export const setupAccountInput = (
mobile = "2014007000",
email = "JohnDoe@gmail.com",
zipCode = "77004",
optedInForMarketing = true,
optedInToRecommendedMessages = true,
optedInToUpdates = true,
optedInToAssociatedCompanies = false,
optedInToThirdParties = false,
optedInToSms = true,
state = "TX",
salesAffiliateSubdomain = null
) => {
let salesSubchannel = "SOME ORGANIZATION"
let communicationPreference = "ONLINE"
let languagePreference = "ENGLISH"
return {
"accountUser": {
"givenName": "John",
"familyName": "Doe",
"email": email,
"mobile": mobile,
"landline": "4407701608",
"communicationPreference": communicationPreference,
"languagePreference": languagePreference,
"dateOfBirth": new Date("1991-01-01").toLocaleDateString('en-CA', { year: 'numeric', month: '2-digit', day: '2-digit' })
},
"billingAddress": {
"address1": "13th Madison Avenue",
"address2": "Apartment number 207",
"city": "Austin",
"state": state,
"zipCode": zipCode,
},
"salesInformation": {
"salesSubchannel": salesSubchannel,
"salesAffiliateSubdomain": salesAffiliateSubdomain,
"optedInForMarketing": optedInForMarketing,
"optedInToRecommendedMessages": optedInToRecommendedMessages,
"optedInToUpdates": optedInToUpdates,
"optedInToAssociatedCompanies": optedInToAssociatedCompanies,
"optedInToThirdParties": optedInToThirdParties,
"optedInToSms": optedInToSms,
},
}
}
export const mutation = `
mutation createAccount($input:CreateAccountInput!){
createAccount(input:$input){
__typename
account{
number
__typename
}
}
}
`
let input = setupAccountInput()
export const variables = {"input": input}
axios({
url: apiUrl,
method: "post",
data: {
query: mutation,
variables: variables,
},
headers: headers,
}).then((response) => {
console.log(JSON.stringify(response.data, null, 4));
});
Expected error messages
- Check for a valid email address.
- If it receives an invalid email address, it will raise
Invalid email address: {email}."
error.
- If it receives an invalid email address, it will raise
- Check for a valid USA zip code.
- If it receives an invalid zipcode, it will raise
'{zip_code}' is not a valid USA postcode."
error.
- If it receives an invalid zipcode, it will raise
- Check for a valid USA phone number.
- If it finds an invalid mobile/landline/phone number, it will raise
'{mobile/landline/phone number}' is not a valid phone number"
error.
- If it finds an invalid mobile/landline/phone number, it will raise
- For any other errors, it will return a generic errror message such as
Cannot create an account.
Add credit score for an account¶
If you are using your own credit service, we require that you send us the credit score using the storeCreditScore
mutation
Check credit score status¶
It is important that you check the credit score status to verify if the customer needs to pay a deposit or not. The status can be one of the following:
PASSED
FAILED
NOT_AVAILABLE
If you've received a FAILED
status, we either require a deposit from the customer or we request our affiliates to recommend our prepay products. If the customer has still choosen to pay a deposit, we require them to contact us. Soon this will be handled via an API call.
Authentication Required
Requires CAN_CREATE_ACCOUNTS
permission.
-
Arguments
accountNumber
:String!
-
Returns
Expected error messages
- If the given account number is invalid/not found.
- It returns -
Unauthorized.
- It returns -
You are not authorized to view this account's credit score status.
Add property and product¶
In this example we've asserted the following scenario:
- The customer wants to perform a move in request which is suggested by the
PENDING_MOVE_IN_REQUEST
enum as an input for theenrollmentType
. -
The customer has selected a product with the id:
18
and they've agreed to it's rates. You can get the product id by using the following how to guides:
Authentication Required
Requires CAN_ADD_PROPERTIES_TO_SHELL_ACCOUNTS
permissions.
-
Arguments
-
Returns
addPropertyToShellAccountData
: AddPropertyToShellAccount
Info
If you do not provide an effectiveFrom
input to addPropertyToShellAccount
, the switch/move-in request will
default to the current CST time. In other words, if a customer wants to switch on the next day, but if we don't
receive that input, instead of switching them tomorrow, we might send a switch request for today.
Note: effectiveFrom
should always be in UTC and follow the iso8601 standard.
For postpay
product¶
import datetime
import pprint
import requests
# API_URL = "https://api.oeus-kraken.energy/v1/graphql/" # prod
API_URL = "https://api.oeus-kraken.systems/v1/graphql/" # test
JWT_TOKEN = "PLACE_JWT_TOKEN_HERE"
HEADERS = {
"Authorization": f"JWT {JWT_TOKEN}"
}
input = {
"accountNumber": "A-B8AAF52D",
"esiId": "1008901000141570010100",
"addressLine1": "26197 Avenue",
"addressLine2": "Shady Woods",
"addressLine3": "St",
"city": "Houston",
"state": "TX",
"postcode": "77057",
"enrollmentType": "PENDING_MOVE_IN_REQUEST",
"productId": "18",
# Without an effectiveFrom input, the request will
# default to the current CST time.
"effectiveFrom": "2022-03-17T21:00:00-05:00",
}
QUERY = """
mutation addPropertyToShellAccount(
$input: AddPropertyToShellAccountInputType!
) {
addPropertyToShellAccount(input: $input) {
addPropertyToShellAccountData {
esiId
}
}
}
"""
VARIABLES = {"input": input}
session = requests.Session()
session.headers.update(HEADERS)
response = session.post(
url=API_URL,
json={"query": QUERY, "variables": VARIABLES}
)
pprint.pprint(response.json())
const axios = require("axios")
// const apiUrl = "https://api.oeus-kraken.energy/v1/graphql/" // Prod
const apiUrl = "https://api.oeus-kraken.systems/v1/graphql/" // Test
const jwtToken = "PLACE_JWT_TOKEN_HERE"
let headers = {
"Authorization": `JWT ${jwtToken}`
}
const input = {
"accountNumber": "A-B8AAF52D",
"esiId": "1008901000141570010101",
"addressLine1": "26197 Avenue",
"addressLine2": "Shady Woods",
"addressLine3": "Lane",
"city": "Houston",
"state": "TX",
"postcode": "77057",
"enrollmentType": "PENDING_MOVE_IN_REQUEST",
"productId": "18",
// Without an effectiveFrom input, the request will
// default to the current CST time.
"effectiveFrom": new Date("2022-03-17T21:00:00-05:00")
};
const mutation = `
mutation addPropertyToShellAccount(
$input: AddPropertyToShellAccountInputType!
) {
addPropertyToShellAccount(input: $input) {
addPropertyToShellAccountData {
esiId
}
}
}
`
const variables = {"input": input}
axios({
url: apiUrl,
method: "post",
data: {
query: mutation,
variables: variables,
},
headers: headers,
}).then((response) => {
console.log(JSON.stringify(response.data, null, 4));
});
import axios from 'axios';
// const API_URL = "https://api.oeus-kraken.energy/v1/graphql/" // Prod
export const apiUrl = "https://api.oeus-kraken.systems/v1/graphql/" // Test
export const jwtToken = "PLACE_JWT_TOKEN_HERE"
let headers = {"Authorization": `JWT ${jwtToken}`}
let input = {
"accountNumber": "A-B8AAF52D",
"esiId": "1008901000141570010101",
"addressLine1": "26197 Avenue",
"addressLine2": "Shady Woods",
"addressLine3": "Lane",
"city": "Houston",
"state": "TX",
"postcode": "77057",
"enrollmentType": "PENDING_MOVE_IN_REQUEST",
"productId": "18",
// Without an effectiveFrom input, the request will
// default to the current CST time.
"effectiveFrom": new Date("2022-03-17T21:00:00-05:00")
};
export const mutation = `
mutation addPropertyToShellAccount(
$input: AddPropertyToShellAccountInputType!
) {
addPropertyToShellAccount(input: $input) {
addPropertyToShellAccountData {
esiId
}
}
}
`
export const variables = {"input": input}
axios({
url: apiUrl,
method: "post",
data: {
query: mutation,
variables: variables,
},
headers: headers,
}).then((response) => {
console.log(JSON.stringify(response.data, null, 4));
});
For prepay
product¶
Customers could choose what amount they're willing to allow us takeout to top up their account once their balance reaches a threshold. This amount should be passed via the autoTopUpPaymentAmount
in this mutation.
import datetime
import pprint
import requests
# API_URL = "https://api.oeus-kraken.energy/v1/graphql/" # prod
API_URL = "https://api.oeus-kraken.systems/v1/graphql/" # test
JWT_TOKEN = "PLACE_JWT_TOKEN_HERE"
HEADERS = {
"Authorization": f"JWT {JWT_TOKEN}"
}
input = {
"accountNumber": "A-B8AAF52D",
"esiId": "1008901000141570010101",
"addressLine1": "26197 Avenue",
"addressLine2": "Shady Woods",
"addressLine3": "Lane",
"city": "Houston",
"state": "TX",
"postcode": "77057",
"enrollmentType": "PENDING_MOVE_IN_REQUEST",
"productId": "18",
# autoTopUpPaymentAmount is in cents
"autoTopUpPaymentAmount": 1500,
# Without an effectiveFrom input, the request will
# default to the current CST time.
"effectiveFrom": "2022-03-17T21:00:00-05:00",
}
QUERY = """
mutation addPropertyToShellAccount(
$input: AddPropertyToShellAccountInputType!
) {
addPropertyToShellAccount(input: $input) {
addPropertyToShellAccountData {
esiId
}
}
}
"""
VARIABLES = {"input": input}
session = requests.Session()
session.headers.update(HEADERS)
response = session.post(
url=API_URL,
json={"query": QUERY, "variables": VARIABLES}
)
pprint.pprint(response.json())
const axios = require("axios")
// const apiUrl = "https://api.oeus-kraken.energy/v1/graphql/" // Prod
const apiUrl = "https://api.oeus-kraken.systems/v1/graphql/" // Test
const jwtToken = "PLACE_JWT_TOKEN_HERE"
let headers = {
"Authorization": `JWT ${jwtToken}`
}
const input = {
"accountNumber": "A-B8AAF52D",
"esiId": "1008901000141570010101",
"addressLine1": "26197 Avenue",
"addressLine2": "Shady Woods",
"addressLine3": "Lane",
"city": "Houston",
"state": "TX",
"postcode": "77057",
"enrollmentType": "PENDING_MOVE_IN_REQUEST",
"productId": "18",
// autoTopUpPaymentAmount is in cents
"autoTopUpPaymentAmount": "1500",
// Without an effectiveFrom input, the request will
// default to the current CST time.
"effectiveFrom": new Date("2022-03-17T21:00:00-05:00")
};
const mutation = `
mutation addPropertyToShellAccount(
$input: AddPropertyToShellAccountInputType!
) {
addPropertyToShellAccount(input: $input) {
addPropertyToShellAccountData {
esiId
}
}
}
`
const variables = {"input": input}
axios({
url: apiUrl,
method: "post",
data: {
query: mutation,
variables: variables,
},
headers: headers,
}).then((response) => {
console.log(JSON.stringify(response.data, null, 4));
});
import axios from 'axios';
// const API_URL = "https://api.oeus-kraken.energy/v1/graphql/" // Prod
export const apiUrl = "https://api.oeus-kraken.systems/v1/graphql/" // Test
export const jwtToken = "PLACE_JWT_TOKEN_HERE"
let headers = {"Authorization": `JWT ${jwtToken}`}
let input = {
"accountNumber": "A-B8AAF52D",
"esiId": "1008901000141570010101",
"addressLine1": "26197 Avenue",
"addressLine2": "Shady Woods",
"addressLine3": "Lane",
"city": "Houston",
"state": "TX",
"postcode": "77057",
"enrollmentType": "PENDING_MOVE_IN_REQUEST",
"productId": "18",
// autoTopUpPaymentAmount is in cents
"autoTopUpPaymentAmount": "1500",
// Without an effectiveFrom input, the request will
// default to the current CST time.
"effectiveFrom": new Date("2022-03-17T21:00:00-05:00")
};
export const mutation = `
mutation addPropertyToShellAccount(
$input: AddPropertyToShellAccountInputType!
) {
addPropertyToShellAccount(input: $input) {
addPropertyToShellAccountData {
esiId
}
}
}
`
export const variables = {"input": input}
axios({
url: apiUrl,
method: "post",
data: {
query: mutation,
variables: variables,
},
headers: headers,
}).then((response) => {
console.log(JSON.stringify(response.data, null, 4));
});
Expected error messages
UNAUTHORIZED
- If the given account number is invalid/not found.
Product not found
- If the given product id is invalid/not found.
Given ESI ID: {esi_id} is not served by us.
- If the given ESI ID is served by a service provider in which Octopus Energy USA does not operate.
Cannot reassign property for account: {account.number} with the given effective at value : {effective_at}.
- Customer will need to manually contact the operations team to handle this case.
Existing meter point with the status: {meter_point.status} cannot be reassigned. Meter point should have one of the ['LOST', 'INITIAL', 'CANCELLED_APPLICATION'] statuses to be reassigned.
- Customer will need to manually contact the operations team to handle this case.