Business Numbers
A business number is a customer-facing phone number on your Phone.inc account — the one you'd publish on a website or business card. Every call and voicemail belongs to exactly one business number. Beyond listing them, you can retrieve the full settings (routing, business hours) and update them through the API.
The business number model
Each business number has a stable public id, the human label your team uses to identify it (name), the underlying phone number, and its full routing configuration.
Properties
- Name
id- Type
- string
- Description
Unique identifier for the business number.
- Name
name- Type
- string
- Description
The label your team set for this number, like
SalesorSupport. ASCII letters, numbers, spaces, and-_~!.+only, up to 128 characters (no accented characters).
- Name
number- Type
- string
- Description
The phone number in E.164 format, e.g.
+14155551234.
- Name
number_formatted- Type
- string
- Description
The same number formatted for display, e.g.
+1 415-555-1234.
- Name
status- Type
- string
- Description
provisioning,active,failed, orterminated. Scheduled numbers remain active untiltermination_at.
- Name
termination_at- Type
- string | null
- Description
ISO 8601 date when service ends permanently. Null when no termination is scheduled.
- Name
released_at- Type
- string | null
- Description
ISO 8601 date when the provider release completed. Released numbers are omitted from the list but remain retrievable by ID with their history.
- Name
messaging- Type
- object
- Description
Provider capabilities:
smsandmmseach contain booleancan_sendandcan_receiveflags. Clients can use these directly for messaging availability. Currently only inMobile SMS is supported; MMS capabilities are false.
- Name
timezone- Type
- string
- Description
IANA timezone for the business number, e.g.
CopenhagenorLondon.
- Name
language- Type
- string
- Description
Language code used for automated messages, e.g.
daoren.
- Name
recording_enabled- Type
- boolean
- Description
Legacy compatibility field.
truewhen either transcription or recording retention is enabled. Setting this field updates bothtranscribe_callsandkeep_call_recording.
- Name
transcribe_calls- Type
- boolean
- Description
Whether calls are recorded and transcribed. When
keep_call_recordingis false, the temporary recording is deleted after transcription completes.
- Name
keep_call_recording- Type
- boolean
- Description
Whether the call recording is stored, including when
transcribe_callsis false.
- Name
call_data_retention- Type
- string
- Description
When transcriptions, summaries, stored caller context, and call recordings are automatically deleted. One of
one_week,one_month,six_months,one_year, ornever. New business numbers default toone_year; numbers that existed when retention policies were introduced default tonever.
- Name
incoming_call_config- Type
- object
- Description
The routing configuration for incoming calls. Contains a
typefield plus type-specific attributes.
- Name
outside_business_hours_config- Type
- object | null
- Description
The routing configuration used outside business hours, or
nullif not set (falls back to incoming call config). Newly created numbers start with a defaultVoicemailConfighere, greeting callers in the number's language; numbers created before this default may still benull.
- Name
no_answer_config- Type
- object | null
- Description
The routing configuration that runs when a call is transferred to employees but nobody answers within the ring timer, or
nullif no fallback is set. Same shape as the other two configs.
- Name
no_answer_timeout_secs- Type
- integer | null
- Description
How long a caller waits for an available employee before the
no_answer_configtakes over.null(or0) means Off: the caller waits until someone answers or they hang up. Allowed values:15,30,60,300,600,1200,1800,2700,3600. Every employee-transfer step queues the same way (in-hours, outside hours, menu branches, and no-answer fallbacks that transfer to employees). Only available employees are rung; callers wait in order. Voicemail and reject after hours never enqueue.
- Name
wait_audio- Type
- string
- Description
What the caller hears while waiting for an employee.
ringtone(default, Nordic ringback) ormusic. Number-level, so a menu that transfers uses the same sound.
- Name
registration_status- Type
- string
- Description
Registration status of the business identity behind the number. One of
not_required,pending,submitted,approved,rejected, orfailed. Where a country regulates the number, we register it to your company's business identity and address, and it moves frompendingtosubmittedtoapproved.not_requiredmeans no registration applies — usually because the number's country does not ask for one, in which case our carrier will not accept a registration even if we offer it. Numbers that did not come from us also reportnot_required.rejectedmeans the carrier reviewed the registration and turned it down.failedmeans we could not submit it at all, usually because the company details we hold are incomplete. Both leave the number reachable but unregistered, and both need someone to act — get in touch if a number stays in either state.
- Name
registration_due_at- Type
- string | null
- Description
ISO 8601 timestamp indicating when the end-user registration must be completed for this number, or
nullif no registration is required. The number remains active during this window.
- Name
business_hours- Type
- array
- Description
Array of 7 objects (one per weekday) defining the opening schedule.
Call flow config types
All three routing slots — incoming_call_config, outside_business_hours_config, and no_answer_config — share the same set of config types:
| Type | Fields |
|---|---|
WelcomeTransferConfig | welcome (string), either employee_ids (non-empty array of strings) or department_id (public UUID) |
TransferConfig | Either employee_ids (non-empty array of strings) or department_id (public UUID) |
RejectConfig | message (string) |
VoicemailConfig | greeting (string) |
PhoneMenuConfig | welcome (string), menu_options (non-empty array) |
TransferConfig transfers the call to the chosen employees without playing a welcome message — it's WelcomeTransferConfig minus the greeting.
Every generated message (welcome, greeting, message, and each menu option's prompt) is limited to 150 whitespace-separated words and 1,500 characters, excluding leading and trailing whitespace. This is roughly one minute of speech, not an exact audio-duration limit: voice and speaking pace vary. Both limits apply to all three routing configurations and voice previews. Overlong text is rejected with 422 before audio generation; it is never silently truncated.
Transfer configs must select either non-empty employee_ids or a department_id, never both. department_id is a public UUID from the Departments API and works in incoming, outside-hours and no-answer slots. Send employee_ids: [] when replacing employees with a department; send department_id: null when switching back. Without a department, empty employee selection returns 422 and preserves the saved flow. Transfer responses include nullable department_id alongside employee_ids.
Each department has one FIFO queue shared across business numbers and flows. Callers inherit waiting and no-answer rules from the number called, and repeated entry into the same department does not reset their queue timestamp or deadline.
Phone menu options
PhoneMenuConfig plays its welcome greeting, then waits for the caller to press a single digit. Each entry in menu_options maps one digit to an action:
| Field | Type | Description |
|---|---|---|
digit | string | A single key, "1" through "9" only ("0" is rejected). Must be unique within the menu. |
action_type | string | What pressing the digit does (see below). |
prompt | string | Message played before the action runs. Required when action_type is WelcomeTransferConfig, VoicemailConfig, or PlayMessageConfig. |
prompt_recorded | boolean | Read only. true when the prompt is a recording made in the dashboard, in which case prompt is an empty string. |
employee_ids | array of strings | Employee transfer targets. For either transfer action, select non-empty employee_ids or department_id, never both. |
department_id | string or null | Department public UUID for TransferConfig or WelcomeTransferConfig. Callers join its shared queue. Send employee_ids: [] when selecting a department, or department_id: null when switching back to employees. |
action_type is one of:
action_type | What happens when the caller presses the digit |
|---|---|
TransferConfig | Transfer straight to the selected employees or department. |
WelcomeTransferConfig | Play prompt, then transfer to the selected employees or department. |
VoicemailConfig | Play prompt, then record a voicemail. |
PlayMessageConfig | Play prompt, then hang up. |
A menu needs at least one option, and every option's digit must be unique — duplicates or an empty menu_options array are rejected with a 422. On read, the response echoes each option's digit, action_type, prompt (when set), prompt_audio_url (generated audio), employee_ids (resolved to public ids), and nullable department_id. Department menu targets work in incoming, outside-hours, and no-answer menus, using the number's waiting and no-answer settings.
On read, every config that plays spoken text also returns the URL of its generated audio (or null while generation is pending): welcome_audio_url on WelcomeTransferConfig and PhoneMenuConfig, message_audio_url on RejectConfig, and greeting_audio_url on VoicemailConfig. Audio regenerates automatically whenever the text changes. A greeting can also be a recording made in the dashboard: the matching welcome_recorded, message_recorded, greeting_recorded, or prompt_recorded flag is true, the text is an empty string, and the audio URL points at the recording. Recordings are not regenerated when the number's voice changes. Sending new text for that field replaces the recording with generated audio, and the flag turns false. Recordings cannot be created through the API. To hear a text before saving it, use voice previews.
Send { "type": null } to clear the outside_business_hours_config or no_answer_config slot entirely. The incoming_call_config slot can't be cleared.
List all business numbers
Returns every business number on the authenticated employee's company. There's no pagination — companies have a small, finite set of business numbers, so the response is a single array.
The list endpoint returns a lean response (id, name, number, number_formatted) plus each number's messaging capabilities, so a client can tell which numbers can send a text without retrieving each one. Use the retrieve endpoint for full settings including routing config and business hours.
Request
curl https://app.phone.inc/api/v1/business_numbers \
-H "X-Api-Key: $PHONE_INC_API_KEY"
Response
{
"business_numbers": [
{
"id": "0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01",
"name": "Sales",
"number": "+14155551234",
"number_formatted": "+1 415-555-1234",
"messaging": {
"sms": { "can_send": true, "can_receive": true },
"mms": { "can_send": false, "can_receive": false }
}
},
{
"id": "0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c02",
"name": "Support",
"number": "+14155555678",
"number_formatted": "+1 415-555-5678",
"messaging": {
"sms": { "can_send": false, "can_receive": false },
"mms": { "can_send": false, "can_receive": false }
}
}
]
}
Retrieve a business number
Returns the full settings for a single business number, including its incoming call config, outside-hours config, and weekly business hours schedule.
Request
curl https://app.phone.inc/api/v1/business_numbers/0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01 \
-H "X-Api-Key: $PHONE_INC_API_KEY"
Response
{
"id": "0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01",
"name": "Sales",
"number": "+14155551234",
"number_formatted": "+1 415-555-1234",
"timezone": "Copenhagen",
"language": "da",
"recording_enabled": false,
"transcribe_calls": false,
"keep_call_recording": false,
"call_data_retention": "never",
"incoming_call_config": {
"type": "PhoneMenuConfig",
"welcome": "Press 1 for sales, 2 to leave a message",
"welcome_recorded": false,
"welcome_audio_url": "https://app.phone.inc/rails/active_storage/blobs/redirect/...",
"menu_options": [
{
"id": 42,
"digit": "1",
"action_type": "TransferConfig",
"prompt": null,
"prompt_recorded": false,
"prompt_audio_url": null,
"employee_ids": ["019daef1-085e-7000-aaaa-000000000001"]
},
{
"id": 43,
"digit": "2",
"action_type": "VoicemailConfig",
"prompt": "Leave a message after the tone",
"prompt_recorded": false,
"prompt_audio_url": "https://app.phone.inc/rails/active_storage/blobs/redirect/...",
"employee_ids": []
}
]
},
"outside_business_hours_config": {
"type": "RejectConfig",
"message": "We are closed, please call back tomorrow."
},
"no_answer_config": {
"type": "VoicemailConfig",
"greeting": "Sorry we missed you — leave a message after the tone."
},
"no_answer_timeout_secs": 30,
"wait_audio": "ringtone",
"registration_status": "approved",
"registration_due_at": null,
"business_hours": [
{ "day_of_week": 0, "day_name": "Monday", "open": true, "opening_at": "09:00", "closing_at": "17:00" },
{ "day_of_week": 1, "day_name": "Tuesday", "open": true, "opening_at": "09:00", "closing_at": "17:00" },
{ "day_of_week": 2, "day_name": "Wednesday", "open": true, "opening_at": "09:00", "closing_at": "17:00" },
{ "day_of_week": 3, "day_name": "Thursday", "open": true, "opening_at": "09:00", "closing_at": "17:00" },
{ "day_of_week": 4, "day_name": "Friday", "open": true, "opening_at": "09:00", "closing_at": "17:00" },
{ "day_of_week": 5, "day_name": "Saturday", "open": false, "opening_at": "09:00", "closing_at": "17:00" },
{ "day_of_week": 6, "day_name": "Sunday", "open": false, "opening_at": "09:00", "closing_at": "17:00" }
]
}
Update a business number
Updates the scalar fields on a business number. Use the dedicated config endpoints below to change call routing or business hours.
Accepted fields
- Name
name- Type
- string
- Description
The display label for this number. ASCII letters, numbers, spaces, and
-_~!.+only, up to 128 characters.
- Name
timezone- Type
- string
- Description
IANA timezone identifier, e.g.
Copenhagen,London,New_York.
- Name
language- Type
- string
- Description
Language code for automated messages:
da,en, etc.
- Name
recording_enabled- Type
- boolean
- Description
Legacy alias that sets both
transcribe_callsandkeep_call_recordingto the supplied value.
- Name
transcribe_calls- Type
- boolean
- Description
Whether to create call transcriptions.
- Name
keep_call_recording- Type
- boolean
- Description
Whether to retain the audio after transcription completes.
- Name
call_data_retention- Type
- string
- Description
Automatic deletion policy for transcriptions and recordings:
one_week,one_month,six_months,one_year, ornever. New business numbers default toone_year.
Request
curl -X PATCH https://app.phone.inc/api/v1/business_numbers/0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01 \
-H "X-Api-Key: $PHONE_INC_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Sales Hotline", "timezone": "London"}'
Response
{
"id": "0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01",
"name": "Sales Hotline",
"number": "+14155551234",
"number_formatted": "+1 415-555-1234",
"timezone": "London",
"language": "da",
"recording_enabled": false,
"transcribe_calls": false,
"keep_call_recording": false,
"call_data_retention": "never",
"incoming_call_config": { "..." },
"outside_business_hours_config": null,
"no_answer_config": null,
"no_answer_timeout_secs": null,
"business_hours": [ "..." ]
}
Replace incoming call config
Replaces the routing configuration used when a call comes in during business hours. Send the desired type and its required fields. The full business number (with updated config) is returned.
Required fields by type
| Type | Fields |
|---|---|
WelcomeTransferConfig | welcome, either employee_ids (at least one id) or department_id; optional welcome_audio_preview_id |
TransferConfig | Either employee_ids (at least one id) or department_id |
RejectConfig | message; optional message_audio_preview_id |
VoicemailConfig | greeting; optional greeting_audio_preview_id |
PhoneMenuConfig | welcome, menu_options (at least one option); optional welcome_audio_preview_id |
Request
curl -X PUT https://app.phone.inc/api/v1/business_numbers/0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01/incoming_call_config \
-H "X-Api-Key: $PHONE_INC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "WelcomeTransferConfig",
"welcome": "Thanks for calling",
"employee_ids": ["019daef1-085e-7000-aaaa-000000000001", "019daef1-085e-7000-aaaa-000000000002"]
}'
Response
{
"id": "0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01",
"name": "Sales",
"number": "+14155551234",
"number_formatted": "+1 415-555-1234",
"timezone": "Copenhagen",
"language": "da",
"recording_enabled": false,
"transcribe_calls": false,
"keep_call_recording": false,
"call_data_retention": "never",
"incoming_call_config": {
"type": "WelcomeTransferConfig",
"welcome": "Thanks for calling",
"employee_ids": ["019daef1-085e-7000-aaaa-000000000001", "019daef1-085e-7000-aaaa-000000000002"]
},
"outside_business_hours_config": null,
"no_answer_config": null,
"no_answer_timeout_secs": null,
"business_hours": [ "..." ]
}
To set a phone menu instead, send type: "PhoneMenuConfig" with a menu_options array:
Phone menu example
curl -X PUT https://app.phone.inc/api/v1/business_numbers/0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01/incoming_call_config \
-H "X-Api-Key: $PHONE_INC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "PhoneMenuConfig",
"welcome": "Press 1 for sales, 2 to leave a message",
"menu_options": [
{ "digit": "1", "action_type": "TransferConfig", "employee_ids": ["019daef1-085e-7000-aaaa-000000000001"] },
{ "digit": "2", "action_type": "VoicemailConfig", "prompt": "Leave a message after the tone" }
]
}'
Response
{
"id": "0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01",
"name": "Sales",
"number": "+14155551234",
"number_formatted": "+1 415-555-1234",
"timezone": "Copenhagen",
"language": "da",
"recording_enabled": false,
"transcribe_calls": false,
"keep_call_recording": false,
"call_data_retention": "never",
"incoming_call_config": {
"type": "PhoneMenuConfig",
"welcome": "Press 1 for sales, 2 to leave a message",
"welcome_recorded": false,
"welcome_audio_url": "https://app.phone.inc/rails/active_storage/blobs/redirect/...",
"menu_options": [
{
"id": 42,
"digit": "1",
"action_type": "TransferConfig",
"prompt": null,
"prompt_recorded": false,
"prompt_audio_url": null,
"employee_ids": ["019daef1-085e-7000-aaaa-000000000001"]
},
{
"id": 43,
"digit": "2",
"action_type": "VoicemailConfig",
"prompt": "Leave a message after the tone",
"prompt_recorded": false,
"prompt_audio_url": "https://app.phone.inc/rails/active_storage/blobs/redirect/...",
"employee_ids": []
}
]
},
"outside_business_hours_config": null,
"no_answer_config": null,
"no_answer_timeout_secs": null,
"business_hours": [ "..." ]
}
Replace outside-hours config
Replaces the routing configuration used when a call comes in outside business hours. You can also update the business hours schedule in the same request by including the business_hours array. Only business_hours is accepted for the schedule; the retired opening_hours request key and response aliases are no longer supported.
Send { "type": null } to clear the outside-hours config entirely — calls will fall through to the regular incoming call config.
Required fields by type
| Type | Fields |
|---|---|
RejectConfig | message; optional message_audio_preview_id |
WelcomeTransferConfig | welcome, either employee_ids (at least one id) or department_id; optional welcome_audio_preview_id |
TransferConfig | Either employee_ids (at least one id) or department_id |
VoicemailConfig | greeting; optional greeting_audio_preview_id |
PhoneMenuConfig | welcome, menu_options (at least one option); optional welcome_audio_preview_id |
Business hours object
- Name
day_of_week- Type
- integer
- Description
Day index: 0 = Monday, 6 = Sunday.
- Name
open- Type
- boolean
- Description
Whether the line is open on this day.
- Name
opening_at- Type
- string
- Description
Opening time in
HH:MMformat (24-hour).
- Name
closing_at- Type
- string
- Description
Closing time in
HH:MMformat. Use24:00for end of day.
Request
curl -X PUT https://app.phone.inc/api/v1/business_numbers/0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01/outside_business_hours_config \
-H "X-Api-Key: $PHONE_INC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "RejectConfig",
"message": "We are closed, please call back tomorrow.",
"business_hours": [
{ "day_of_week": 0, "open": true, "opening_at": "09:00", "closing_at": "17:00" },
{ "day_of_week": 1, "open": true, "opening_at": "09:00", "closing_at": "17:00" },
{ "day_of_week": 2, "open": true, "opening_at": "09:00", "closing_at": "17:00" },
{ "day_of_week": 3, "open": true, "opening_at": "09:00", "closing_at": "17:00" },
{ "day_of_week": 4, "open": true, "opening_at": "09:00", "closing_at": "17:00" },
{ "day_of_week": 5, "open": false, "opening_at": "09:00", "closing_at": "17:00" },
{ "day_of_week": 6, "open": false, "opening_at": "09:00", "closing_at": "17:00" }
]
}'
Response
{
"id": "0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01",
"name": "Sales",
"number": "+14155551234",
"number_formatted": "+1 415-555-1234",
"timezone": "Copenhagen",
"language": "da",
"recording_enabled": false,
"transcribe_calls": false,
"keep_call_recording": false,
"call_data_retention": "never",
"incoming_call_config": { "..." },
"outside_business_hours_config": {
"type": "RejectConfig",
"message": "We are closed, please call back tomorrow."
},
"no_answer_config": null,
"no_answer_timeout_secs": null,
"business_hours": [
{ "day_of_week": 0, "day_name": "Monday", "open": true, "opening_at": "09:00", "closing_at": "17:00" },
{ "day_of_week": 1, "day_name": "Tuesday", "open": true, "opening_at": "09:00", "closing_at": "17:00" },
{ "day_of_week": 2, "day_name": "Wednesday", "open": true, "opening_at": "09:00", "closing_at": "17:00" },
{ "day_of_week": 3, "day_name": "Thursday", "open": true, "opening_at": "09:00", "closing_at": "17:00" },
{ "day_of_week": 4, "day_name": "Friday", "open": true, "opening_at": "09:00", "closing_at": "17:00" },
{ "day_of_week": 5, "day_name": "Saturday", "open": false, "opening_at": "09:00", "closing_at": "17:00" },
{ "day_of_week": 6, "day_name": "Sunday", "open": false, "opening_at": "09:00", "closing_at": "17:00" }
]
}
Replace no-answer config
Sets the flow that runs when a call is transferred to employees but nobody answers within the ring timer. Send the desired type, its required fields, and timeout_secs to arm the timer.
timeout_secs controls both the ring duration and whether the feature is on. Pass 15, 30, 60, 300, 600, 1200, 1800, 2700, or 3600. Send "", 0, or null to turn it off — calls then ring until they end naturally, exactly as before. Any other value is rejected with a 422.
Send { "type": null } to clear the no-answer flow.
Don't put employees in this flow's WelcomeTransferConfig or TransferConfig and expect another timeout — the no-answer transfer rings without a timer, so it never loops back into itself.
Required fields by type
| Type | Fields |
|---|---|
WelcomeTransferConfig | welcome, either employee_ids (at least one id) or department_id; optional welcome_audio_preview_id |
TransferConfig | Either employee_ids (at least one id) or department_id |
RejectConfig | message; optional message_audio_preview_id |
VoicemailConfig | greeting; optional greeting_audio_preview_id |
PhoneMenuConfig | welcome, menu_options (at least one option); optional welcome_audio_preview_id |
Accepted fields
- Name
type- Type
- string | null
- Description
One of the call flow config types, or
nullto clear the slot.
- Name
timeout_secs- Type
- integer | null
- Description
Ring timer in seconds:
15,30,60,300,600,1200,1800,2700, or3600.0,null, or a blank string ("", coerced to null server-side) turns the no-answer flow off.
Request
curl -X PUT https://app.phone.inc/api/v1/business_numbers/0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01/no_answer_config \
-H "X-Api-Key: $PHONE_INC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "VoicemailConfig",
"greeting": "Sorry we missed you — leave a message after the tone.",
"timeout_secs": 30
}'
Response
{
"id": "0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01",
"name": "Sales",
"number": "+14155551234",
"number_formatted": "+1 415-555-1234",
"timezone": "Copenhagen",
"language": "da",
"recording_enabled": false,
"transcribe_calls": false,
"keep_call_recording": false,
"call_data_retention": "never",
"incoming_call_config": { "..." },
"outside_business_hours_config": null,
"no_answer_config": {
"type": "VoicemailConfig",
"greeting": "Sorry we missed you — leave a message after the tone."
},
"no_answer_timeout_secs": 30,
"business_hours": [ "..." ]
}
Generate a voice preview
Generates a text-to-speech preview of text in the number's voice and language, so you can play a greeting before saving it. Returns a playable audio_url and the preview's signed id.
To reuse the exact preview when saving incoming, outside-business-hours, or no-answer routing, send its signed id as welcome_audio_preview_id for a welcome/menu, message_audio_preview_id for a rejection, or greeting_audio_preview_id for voicemail. The preview must be unused and match the number, audio kind, and text. Generate a separate preview for each routing slot. An omitted or nonmatching preview uses normal speech generation. Unused previews are cleaned up automatically.
Rate limited to 30 previews per minute per company. Exceeding it returns a 429.
Required fields
- Name
kind- Type
- string
- Description
Which field the text belongs to:
welcome,greeting,message, orprompt. Anything else is rejected with a422and codeinvalid_kind.
- Name
text- Type
- string
- Description
The text to speak, up to 150 whitespace-separated words and 1,500 characters. Blank text is rejected with a
422and codeblank_text. Exceeding either limit returns422with codetext_too_long, without calling the synthesis service.
Errors
Voice generation depends on an upstream synthesis service. Failures there (timeouts, rate limits, rejected text, missing configuration) raise and return 500, which Sentry captures. Retrying after a moment is the right response. Validation errors stay 422 (invalid_kind, blank_text, text_too_long). Shorten overlong text before retrying.
Request
curl -X POST https://app.phone.inc/api/v1/business_numbers/0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01/voice_previews \
-H "X-Api-Key: $PHONE_INC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"kind": "welcome",
"text": "Hi, you have reached Harbour & Co."
}'
Response
{
"id": "eyJfcmFpbHMiOnsiZGF0YSI6...",
"kind": "welcome",
"text": "Hi, you have reached Harbour & Co.",
"audio_url": "https://app.phone.inc/rails/active_storage/blobs/..."
}
Request number porting
Replace an existing business number with your old number. The existing number stays active as a temporary number while our team arranges the carrier transfer. When porting completes, your old number takes over the same business-number ID, routing, and settings. The temporary number is terminated. Keep your current provider subscription until the transfer completes.
Available on Free without purchasing a second business number. The temporary number must be active, unreleased, provisioned by DIDWW, without an inventory assignment, scheduled termination, or any previous porting request (including completed or cancelled requests).
Returns 201 with the porting request's public id, business_number_id, normalized number_to_port, and initial status of requested. This records a request for our team; it does not immediately submit a transfer to the carrier. Invalid or ineligible requests return 422 with an errors object. Numbers outside your company and released numbers return 404.
Attributes
- Name
number_to_port- Type
- string
- Description
Required. Your old phone number, including its country code. Must match the temporary number's country dial code, differ from the temporary number, and have no open porting request.
- Name
tax_id- Type
- string
- Description
Required for Danish numbers. A valid eight-digit CVR number, optionally prefixed with
DK.
Request
curl -X POST https://app.phone.inc/api/v1/business_numbers/019daef1-085e-73f0-85f6-a71e2d8dd2cc/porting_request \
-H "X-Api-Key: $PHONE_INC_API_KEY" \
-H "Content-Type: application/json" \
-d '{"number_to_port":"+4533123487","tax_id":"46213564"}'
Response
{
"id": "019daef1-085f-7000-8000-a71e2d8dd2cc",
"business_number_id": "019daef1-085e-73f0-85f6-a71e2d8dd2cc",
"number_to_port": "+4533123487",
"status": "requested"
}
Terminate a business number
Permanently close a number at the end of its current billing period. It stays active until termination_at. You can cancel termination before that deadline. The number cannot be recovered after closure; call history is retained. Obtain explicit confirmation before sending this request.
The number charge is removed from future bills immediately, without prorating or refunding the current period. The free-number credit moves to the oldest remaining, non-terminating active number. Employee charges and the company subscription are unchanged, including when terminating the last number.
Requires an active subscription and an active number without an ongoing port. Returns 422 if these conditions or a future billing period end are unavailable, and 503 if Stripe cannot be updated. Repeated requests return the same termination date. The deprecated /main_numbers/:id/termination route is also supported.
Required attributes
- Name
confirm- Type
- boolean
- Description
Must be
trueto acknowledge permanent termination.
Request
curl -X POST https://app.phone.inc/api/v1/business_numbers/019daef1-085e-73f0-85f6-a71e2d8dd2cc/termination \
-H "X-Api-Key: $PHONE_INC_API_KEY" \
-H "Content-Type: application/json" \
-d '{"confirm":true}'
Returns the full business-number object, including:
Response fields
{
"id": "019daef1-085e-73f0-85f6-a71e2d8dd2cc",
"status": "active",
"termination_at": "2026-11-01T00:00:00Z",
"released_at": null
}
Cancel a termination
Cancel a scheduled termination before termination_at. The number stays active and resumes normal renewal. No extra charge is prorated for the current period, which was already paid. The free-number credit is recalculated across the remaining active numbers, so the oldest eligible number receives the discount.
Returns the full business-number object with termination_at: null. Repeating the request on an active number with no scheduled termination succeeds without changing billing. Previously queued closure jobs will not release the number.
Returns 422 at or after the closure deadline, or when billing cannot be restored automatically. Released numbers return 404. Stripe failures return 503 and leave termination scheduled. Requires an active billing subscription. The deprecated /main_numbers/:id/termination route is also supported.
No request body is required.
Request
curl -X DELETE https://app.phone.inc/api/v1/business_numbers/019daef1-085e-73f0-85f6-a71e2d8dd2cc/termination \
-H "X-Api-Key: $PHONE_INC_API_KEY"
Returns the full business-number object, including:
Response fields
{
"id": "019daef1-085e-73f0-85f6-a71e2d8dd2cc",
"status": "active",
"termination_at": null,
"released_at": null
}
Send an SMS
Send a message from an active inMobile business number. The optional JSON body field format defaults to sms; only sms is currently supported, and mms or unknown formats return 422 before persistence or provider dispatch. Use /business_numbers/:id/messages; the old /business_numbers/:id/sms_messages sending URL is not exposed. The server derives the sender from the selected number, so clients cannot override it.
The authenticated employee must belong to the company that owns the number. Company API keys are supported only while their creator employee still belongs to that company. Keys without a creator employee cannot send SMS. Missing credentials return 401; missing or mismatched employee membership returns 403. Unknown numbers and numbers belonging to another company return 404.
Required attributes
- Name
business_number_id- Type
- string
- Description
Business number public ID in the URL. Only active inMobile numbers with at most 14 digits can send.
- Name
to- Type
- string
- Description
Recipient in E.164 format, such as
+4523909778. Include the country code. National-format numbers are not accepted.
- Name
text- Type
- string
- Description
SMS text, between 1 and 10,000 characters. Whitespace-only text is rejected. Encoding is automatic: GSM-7 when possible, UCS-2 for Unicode. Longer messages can require multiple chargeable SMS parts.
Response
The number's messaging.sms.can_send capability must be true, including an associated inventory record marked SMS-capable. If that record is missing or its SMS capability is disabled, sending returns 422 without creating a message or contacting the provider. Its existing provider handles both voice and messaging. The company's messaging feature flag must be enabled by Phone.inc; it defaults to off. While disabled, message endpoints return 404 and messaging.sms.can_send is false. The message is stored before contacting the provider. 202 Accepted does not mean the recipient received it. The body is a persisted SMS activity item, with a stable Phone.inc ID, employee author, timestamps, and delivery state. A replay returns the current state, which may already be delivered, failed, or unknown.
- Name
id- Type
- string
- Description
- Stable Phone.inc message public ID, shared by history and retries.
- Name
business_number_id- Type
- string
- Description
- Sender business number public ID.
- Name
from- Type
- string
- Description
- Server-selected sender in E.164 format.
- Name
to- Type
- string
- Description
- Recipient in E.164 format.
- Name
status- Type
- string
- Description
- Current delivery state, usually
acceptedafter a new send.
- Name
sms_count- Type
- integer
- Description
- Number of SMS parts reported by the provider.
- Name
encoding- Type
- string
- Description
- Provider-selected
gsm7orucs2encoding.
Errors and retries
Invalid input or an unsupported sender returns 422 with { "errors": { ... } }. Provider validation rejection also returns 422, under errors.base. Unconfigured SMS sending returns 503. Provider HTTP, transport, or response errors return 502; these use { "error": "...", "id": "..." } and omit private provider details. Provider errors after persistence include the stable message ID. Changed input with a reused idempotency key returns 409. New sends and explicit retries share a limit of 30 attempts per business number per rolling minute (429, Retry-After: 60); safe replays do not consume another attempt.
Sending an SMS has a real, chargeable side effect. Supply Idempotency-Key or the JSON field idempotency_key (1–128 nonblank characters); the header wins when both are supplied. Reuse the same key only to replay identical recipient, text, and employee input on the same business number. Without a key, each call creates a new message. A timeout or 502 may mean acceptance is unknown: inspect the persisted record rather than sending again with another key. Only definitively failed messages support the explicit retry endpoint.
Provider blacklist protection remains enabled. Scheduling, bulk recipients, custom sender IDs, and caller-supplied callback URLs are not exposed.
Request
curl -X POST https://app.phone.inc/api/v1/business_numbers/0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01/messages \
-H "X-Api-Key: $PHONE_INC_API_KEY" \
-H "Content-Type: application/json" \
-d '{"to":"+4523909778","text":"Your appointment is confirmed.","idempotency_key":"appointment-1"}'
Response
{
"id": "019daef1-085e-73f0-85f6-a71e2d8dd2cc",
"type": "message",
"format": "sms",
"created_at": "2026-10-06T10:41:00.000000Z",
"business_number_name": "Sales",
"seen_at": "2026-10-06T10:41:00.000000Z",
"direction": "outbound",
"text": "Your appointment is confirmed.",
"author": { "type": "employee", "id": "019daef1-085e-73f0-85f6-a71e2d8dd2cd", "name": "Lea" },
"received_at": null,
"delivered_at": null,
"failure_code": null,
"can_retry": false,
"business_number_id": "0193f4a9-7c34-7c00-9e3d-2b2b8a7f1c01",
"from": "+4592450113",
"to": "+4523909778",
"status": "accepted",
"sms_count": 1,
"encoding": "gsm7"
}