Hello
I’m trying to create a multilevel IVR using the /callflow/multilevelivr endpoint, but I keep getting the following error in the API response:
Terminal Output ________________________________________________________
Original area code: 303719 → Chunks: ['303', '719'] → Selected: 719
Processing: Secure Black Forest Chimney Repair Solutions, Black Forest, 719, 848 *** ****
Trying area codes: ['719']
Found: 719 *** **** (ID: 178 ***)
Reserved number 719 *** ****
Creating IVR for 719 *** **** → 848 *** **** | Status: 200
Response: {'result': 'success', 'err': None, 'data': [{'result': 'error', 'data': 'Must have either single number OR number pool defined the same route', 'entry_count': 1}]}"
_____________________________________________________________________
Here’s the situation:
I search for and reserve a number successfully via /number/search and /number/reserve.
Then I try to create an IVR where calls to the reserved number are forwarded to an external phone number (not a Convirza-managed number).
Could you please clarify:
The correct way to configure the payload for forwarding to an external number via /callflow/multilevelivr?
Whether target_did and overflowNumbers are allowed in the same request when using an external destination.
Example of the current payload I’m sending is attached for reference.
import requests
import csv
import re
import random
# ==== CONFIGURATION ====
API_USERNAME = ""
API_PASSWORD = ""
CLIENT_SECRET = ""
CSV_FILE = "business_numbers.csv"
CAMPAIGN_ID = 59****
CHANNEL_ID = 22
GROUP_ID = 59****
API_BASE = "****apicfa.****.com/v2"
# ==== STEP 1: Authenticate ====
def get_access_token():
................
# ==== STEP 2: Search & Reserve Number ====
def buy_number_by_area_code(access_token, area_code):
if len(area_code) > 3:
chunks = [area_code[i:i+3] for i in range(0, len(area_code), 3) if len(area_code[i:i+3]) == 3]
else:
chunks = [area_code]
print(f" Trying area codes: {chunks}")
for code in chunks:
url = f"{API_BASE}/number/search"
params = {"npa": code}
headers = {
"Authorization": f"Bearer {access_token}",
"Accept": "application/json"
}
try:
response = requests.get(url, headers=headers, params=params)
response.raise_for_status()
res_json = response.json()
available_numbers = [
n for n in res_json.get("data", [])
if n.get("number") and n.get("number_id")
]
if not available_numbers:
print(f"
No valid numbers found for area code {code}. Raw response: {res_json}")
continue
chosen_number = random.choice(available_numbers)
print(f" Found: {chosen_number['number']} (ID: {chosen_number['number_id']})")
reserve_payload = [{
"number_id": int(chosen_number["number_id"]),
"number": int(chosen_number["number"]),
"source": int(chosen_number.get("source", 0))
}]
reserve_url = f"{API_BASE}/number/reserve"
reserve_headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
reserve_resp = requests.post(reserve_url, json=reserve_payload, headers=reserve_headers)
if reserve_resp.status_code == 200:
print(f"
Reserved number {chosen_number['number']}")
return chosen_number["number"], chosen_number["number_id"]
else:
print(f"
Failed to reserve {chosen_number['number']}: {reserve_resp.status_code} {reserve_resp.text}")
except requests.RequestException as e:
print(f"
Request failed for area code {code}: {e}")
print("
No numbers available in any provided area code chunks.")
return None, None
# ==== STEP 3: Get Forward Number ID ====
def get_number_id(access_token, phone_number):
"""Look up number_id for an existing number in the account."""
url = f"{API_BASE}/number/search"
params = {"number": phone_number}
headers = {
"Authorization": f"Bearer {access_token}",
"Accept": "application/json"
}
r = requests.get(url, headers=headers, params=params)
r.raise_for_status()
data = r.json().get("data", [])
if data:
return data[0]["number_id"]
return None
# ==== STEP 4: Create IVR ====
def create_multilevel_ivr(access_token, bought_number, number_id, forward_number, forward_number_id, call_flow_name, whisper_message):
url = f"{API_BASE}/callflow/multilevelivr"
headers = {"Authorization": f"Bearer {access_token}", "Content-Type": "application/json"}
ivr_message = f"Thank you for calling {call_flow_name}. Please press 1 to speak to a representative."
payload = [{
"call_flow_name": call_flow_name,
"call_flow_status": "active",
"spam_filter_enabled": True,
"spam_threshold": 1,
"repeat_interval": 72,
"channel_id": CHANNEL_ID,
"campaign_id": CAMPAIGN_ID,
"group_id": GROUP_ID,
"dnis": [
{
"number": str(bought_number),
"number_id": int(number_id)
}
],
"default_ringto": int(forward_number_id),
"play_disclaimer": "before",
"voicemail_enabled": False,
"record_call_enabled": True,
"ring_delay": 18,
"sms_enabled": False,
"message": ivr_message,
"ivrs": [
{
"key": 1,
"action": "simple",
"destination": str(forward_number), # string phone number
"target_did": int(forward_number), # full phone number, not ID
"message": "",
"isSimultaneous": False,
"overflowNumbers": [
{
"overflowNumber": int(forward_number), # full phone number
"rings": 10
}
],
"record_enabled": True,
"play_disclaimer": "never",
"whisper_enabled": True,
"whisper_message": whisper_message,
"voicemail_enabled": False,
"go_back_key": 0
}
]
}]
r = requests.post(url, headers=headers, json=payload)
print(f" Creating IVR for {bought_number} → {forward_number} | Status: {r.status_code}")
try:
print("Response:", r.json())
except:
print("Raw Response:", r.text)
return r.status_code == 200
# ==== Utilities ====
def remove_special_characters(text):
return re.sub(r'[^A-Za-z0-9 ]+', '', text)
def get_first_word(text):
return str(text).split()[0] if text else ""
def normalize_area_code(area_code_str):
digits = ''.join(filter(str.isdigit, area_code_str))
if len(digits) <= 3:
return digits
chunks = [digits[i:i+3] for i in range(0, len(digits), 3)]
chosen = random.choice(chunks)
print(f"Original area code: {area_code_str} → Chunks: {chunks} → Selected: {chosen}")
return chosen
# ==== MAIN ====
if __name__ == "__main__":
token = get_access_token()
with open(CSV_FILE, newline='', encoding='utf-8') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
business_name = remove_special_characters(row["Business name"].strip())
city = remove_special_characters(row["City"].strip())
area_code = normalize_area_code(row["area code"].strip())
forward_number = re.sub(r'\D', '', row["forwarder Number"])
print(f"Processing: {business_name}, {city}, {area_code}, {forward_number}")
if not (business_name and city and area_code and forward_number):
print(f"
Missing data in row: {row}")
continue
whisper_message = f"{get_first_word(business_name)} Chimney Sweep {city} co"
call_flow_name = business_name
bought_number, number_id = buy_number_by_area_code(token, area_code)
if bought_number and number_id:
forward_number_id = get_number_id(token, forward_number)
if not forward_number_id:
print(f"
Could not find number_id for forward number {forward_number}")
continue
success = create_multilevel_ivr(
token,
str(bought_number),
int(number_id),
str(forward_number),
int(forward_number_id),
call_flow_name,
whisper_message
)
with open("success_numbers.txt" if success else "missing_numbers.txt", "a") as log:
log.write(f"{bought_number}\t{call_flow_name}\n")
Thank you
I’m trying to create a multilevel IVR using the /callflow/multilevelivr endpoint, but I keep getting the following error in the API response:
Terminal Output ________________________________________________________
Original area code: 303719 → Chunks: ['303', '719'] → Selected: 719
Processing: Secure Black Forest Chimney Repair Solutions, Black Forest, 719, 848 *** ****
Trying area codes: ['719']
Found: 719 *** **** (ID: 178 ***)
Reserved number 719 *** ****
Creating IVR for 719 *** **** → 848 *** **** | Status: 200
Response: {'result': 'success', 'err': None, 'data': [{'result': 'error', 'data': 'Must have either single number OR number pool defined the same route', 'entry_count': 1}]}"
_____________________________________________________________________
Here’s the situation:
I search for and reserve a number successfully via /number/search and /number/reserve.
Then I try to create an IVR where calls to the reserved number are forwarded to an external phone number (not a Convirza-managed number).
Could you please clarify:
The correct way to configure the payload for forwarding to an external number via /callflow/multilevelivr?
Whether target_did and overflowNumbers are allowed in the same request when using an external destination.
Example of the current payload I’m sending is attached for reference.
import requests
import csv
import re
import random
# ==== CONFIGURATION ====
API_USERNAME = ""
API_PASSWORD = ""
CLIENT_SECRET = ""
CSV_FILE = "business_numbers.csv"
CAMPAIGN_ID = 59****
CHANNEL_ID = 22
GROUP_ID = 59****
API_BASE = "****apicfa.****.com/v2"
# ==== STEP 1: Authenticate ====
def get_access_token():
................
# ==== STEP 2: Search & Reserve Number ====
def buy_number_by_area_code(access_token, area_code):
if len(area_code) > 3:
chunks = [area_code[i:i+3] for i in range(0, len(area_code), 3) if len(area_code[i:i+3]) == 3]
else:
chunks = [area_code]
print(f" Trying area codes: {chunks}")
for code in chunks:
url = f"{API_BASE}/number/search"
params = {"npa": code}
headers = {
"Authorization": f"Bearer {access_token}",
"Accept": "application/json"
}
try:
response = requests.get(url, headers=headers, params=params)
response.raise_for_status()
res_json = response.json()
available_numbers = [
n for n in res_json.get("data", [])
if n.get("number") and n.get("number_id")
]
if not available_numbers:
print(f"
continue
chosen_number = random.choice(available_numbers)
print(f" Found: {chosen_number['number']} (ID: {chosen_number['number_id']})")
reserve_payload = [{
"number_id": int(chosen_number["number_id"]),
"number": int(chosen_number["number"]),
"source": int(chosen_number.get("source", 0))
}]
reserve_url = f"{API_BASE}/number/reserve"
reserve_headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
reserve_resp = requests.post(reserve_url, json=reserve_payload, headers=reserve_headers)
if reserve_resp.status_code == 200:
print(f"
return chosen_number["number"], chosen_number["number_id"]
else:
print(f"
except requests.RequestException as e:
print(f"
print("
return None, None
# ==== STEP 3: Get Forward Number ID ====
def get_number_id(access_token, phone_number):
"""Look up number_id for an existing number in the account."""
url = f"{API_BASE}/number/search"
params = {"number": phone_number}
headers = {
"Authorization": f"Bearer {access_token}",
"Accept": "application/json"
}
r = requests.get(url, headers=headers, params=params)
r.raise_for_status()
data = r.json().get("data", [])
if data:
return data[0]["number_id"]
return None
# ==== STEP 4: Create IVR ====
def create_multilevel_ivr(access_token, bought_number, number_id, forward_number, forward_number_id, call_flow_name, whisper_message):
url = f"{API_BASE}/callflow/multilevelivr"
headers = {"Authorization": f"Bearer {access_token}", "Content-Type": "application/json"}
ivr_message = f"Thank you for calling {call_flow_name}. Please press 1 to speak to a representative."
payload = [{
"call_flow_name": call_flow_name,
"call_flow_status": "active",
"spam_filter_enabled": True,
"spam_threshold": 1,
"repeat_interval": 72,
"channel_id": CHANNEL_ID,
"campaign_id": CAMPAIGN_ID,
"group_id": GROUP_ID,
"dnis": [
{
"number": str(bought_number),
"number_id": int(number_id)
}
],
"default_ringto": int(forward_number_id),
"play_disclaimer": "before",
"voicemail_enabled": False,
"record_call_enabled": True,
"ring_delay": 18,
"sms_enabled": False,
"message": ivr_message,
"ivrs": [
{
"key": 1,
"action": "simple",
"destination": str(forward_number), # string phone number
"target_did": int(forward_number), # full phone number, not ID
"message": "",
"isSimultaneous": False,
"overflowNumbers": [
{
"overflowNumber": int(forward_number), # full phone number
"rings": 10
}
],
"record_enabled": True,
"play_disclaimer": "never",
"whisper_enabled": True,
"whisper_message": whisper_message,
"voicemail_enabled": False,
"go_back_key": 0
}
]
}]
r = requests.post(url, headers=headers, json=payload)
print(f" Creating IVR for {bought_number} → {forward_number} | Status: {r.status_code}")
try:
print("Response:", r.json())
except:
print("Raw Response:", r.text)
return r.status_code == 200
# ==== Utilities ====
def remove_special_characters(text):
return re.sub(r'[^A-Za-z0-9 ]+', '', text)
def get_first_word(text):
return str(text).split()[0] if text else ""
def normalize_area_code(area_code_str):
digits = ''.join(filter(str.isdigit, area_code_str))
if len(digits) <= 3:
return digits
chunks = [digits[i:i+3] for i in range(0, len(digits), 3)]
chosen = random.choice(chunks)
print(f"Original area code: {area_code_str} → Chunks: {chunks} → Selected: {chosen}")
return chosen
# ==== MAIN ====
if __name__ == "__main__":
token = get_access_token()
with open(CSV_FILE, newline='', encoding='utf-8') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
business_name = remove_special_characters(row["Business name"].strip())
city = remove_special_characters(row["City"].strip())
area_code = normalize_area_code(row["area code"].strip())
forward_number = re.sub(r'\D', '', row["forwarder Number"])
print(f"Processing: {business_name}, {city}, {area_code}, {forward_number}")
if not (business_name and city and area_code and forward_number):
print(f"
continue
whisper_message = f"{get_first_word(business_name)} Chimney Sweep {city} co"
call_flow_name = business_name
bought_number, number_id = buy_number_by_area_code(token, area_code)
if bought_number and number_id:
forward_number_id = get_number_id(token, forward_number)
if not forward_number_id:
print(f"
continue
success = create_multilevel_ivr(
token,
str(bought_number),
int(number_id),
str(forward_number),
int(forward_number_id),
call_flow_name,
whisper_message
)
with open("success_numbers.txt" if success else "missing_numbers.txt", "a") as log:
log.write(f"{bought_number}\t{call_flow_name}\n")
Thank you