Assign a phone number

Buy a phone number and attach it to one agent. This save completes the "Assign Number" task.

POSThttps://api.spyne.ai/console/v1/telephony/phone-numbers
AuthBearer token (console user)Rate limit5 requests / hour per dealer group and 5 per userProcessingSynchronous; waits for purchase, messaging attach, save and call routingWarningEvery success buys a real US phone number from the carrier and bills for it. Do not send unless you mean to buy a number.

Every success buys a real number from the carrier and bills for it. You cannot choose the area code or the country: the number is the first available local US number that can take voice and SMS, so it is not matched to the rooftop's location.

Auth: Bearer token of a signed-in console user, checked with the identity service. The token must carry a dealer group, and that dealer group must match the body's enterpriseId. Rate limit: 5 requests per dealer group and 5 per user in each fixed one-hour window aligned to the clock hour. Processing: synchronous. The call waits for the number purchase, the messaging-service attach, the save and the call routing.

Before you call it

  • The agent must exist (Create an agent). Get teamAgentMappingId from List agents.
  • In the console UI, the "Assign Number" task stays locked until "Agent Customization" is done.
  • Check phoneNumber in List agents first. For an inbound agent that already has an active number, the call returns that number and buys nothing. For an outbound agent there is no such check: every call buys a new number.
  • Both rate limits must pass. Every authenticated request counts, even one later rejected by the dealer-group check or the lock. When the limit store is unavailable, every request is rejected with 429.
  • Send Authorization: Bearer YOUR_TOKEN and Content-Type: application/json.

What the console checks

  1. Token check.
  2. Rate limit.
  3. The body's enterpriseId must match the token's dealer group.
  4. The rooftop must belong to that dealer group and be active.
  5. A 60-second lock on this agent blocks a second request for the same agent while one is running.

The console then calls the agent backend with only enterpriseId, teamId and teamAgentMappingId (30-second timeout). The agent backend checks that the agent is active and belongs to this dealer group and rooftop, buys the number from Twilio, and then:

  • attaches the number to the messaging service;
  • saves the number record;
  • routes calls to the rooftop's call provider.

The number is not written to the configuration store's agent record.


Request body

Requiredalways send
Request checklist
  1. Scope it: send enterpriseId (the token's own dealer group), teamId and teamAgentMappingId.
  2. After a 424 timeout: do not retry until you have checked whether a number was attached.
ParameterTypeRequiredDescription
enterpriseIdstringRequiredDealer group. Must match the token.
teamIdstringRequiredRooftop. Must belong to the dealer group and be active.
teamAgentMappingIdstringRequiredAgent the number is for.

Sample request

curl -X POST "https://api.spyne.ai/console/v1/telephony/phone-numbers" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enterpriseId":"<enterpriseId>","teamId":"<teamId>","teamAgentMappingId":"<teamAgentMappingId>"}'
import requests

res = requests.post(
    "https://api.spyne.ai/console/v1/telephony/phone-numbers",
    headers={"Authorization": "Bearer YOUR_TOKEN"},
    json={
        "enterpriseId": "<enterpriseId>",
        "teamId": "<teamId>",
        "teamAgentMappingId": "<teamAgentMappingId>",
    },
)
print(res.status_code, res.json())
const res = await fetch('https://api.spyne.ai/console/v1/telephony/phone-numbers', {
  method: 'POST',
  headers: { Authorization: 'Bearer YOUR_TOKEN', 'Content-Type': 'application/json' },
  body: JSON.stringify({
    enterpriseId: '<enterpriseId>',
    teamId: '<teamId>',
    teamAgentMappingId: '<teamAgentMappingId>',
  }),
});
console.log(res.status, await res.json());

Sample response

{
  "message": "Phone number provisioned successfully",
  "error": false,
  "code": "",
  "details": null,
  "data": {
    "message": "Phone number created and attached successfully",
    "status": "success",
    "provider": "twilio",
    "country": "US",
    "areaCode": null,
    "phoneNumber": "+1XXXXXXXXXX",
    "phoneNumberSid": "<phoneNumberSid>",
    "enterpriseId": "<enterpriseId>",
    "teamId": "<teamId>",
    "teamAgentMappingId": "<teamAgentMappingId>",
    "callProvider": "<callProvider>",
    "webhookOwner": "<webhookOwner>",
    "webhookUrl": "https://example.com/webhook",
    "messagingServiceSid": "<messagingServiceSid>",
    "vapiPhoneNumberId": null
  }
}
{
  "message": "Phone number provisioned successfully",
  "error": false,
  "code": "",
  "details": null,
  "data": {
    "message": "Phone number is already attached to this teamAgentMappingId",
    "status": "success",
    "alreadyExists": true,
    "created": false,
    "phoneNumber": "+1XXXXXXXXXX",
    "teamAgentMappingId": "<teamAgentMappingId>"
  }
}
{ "message": "No available phone numbers found in US", "error": true, "code": "ERROR_BAD_REQ_400", "details": null, "data": null }
{ "message": "Invalid Token", "error": true, "code": "ERROR_AUTH_401", "details": "", "data": null }
{ "message": "You cannot purchase a phone number for another enterprise.", "error": true, "code": "ERROR_FORBIDDEN_403", "details": null, "data": null }
{ "message": "That rooftop does not exist on your enterprise.", "error": true, "code": "ERROR_NOT_FOUND_404", "details": null, "data": null }
{ "message": "A phone number request for this agent is already in progress. Please wait for it to finish.", "error": true, "code": "ERROR_CONFLICT_409", "details": null, "data": null }
{ "message": "The phone number request did not complete in time. Do NOT retry immediately — check whether a number was assigned before trying again.", "error": true, "code": "ERROR_FAILED_DEPENDENCY_424", "details": null, "data": null }
{ "message": "This enterprise has purchased too many phone numbers in a short period. Please try again later.", "error": true, "code": "ERROR_TOO_MANY_REQUESTS_429", "details": null, "data": null }
{ "message": "Could not provision a phone number right now. Please try again.", "error": true, "code": "ERROR_SERVER_500", "details": null, "data": null }

Response parameters (200)

ParameterTypeDescription
messagestringPhone number provisioned successfully. Also returned when an existing number is reused.
errorbooleanfalse on success.
code, detailsstring or nullEmpty on success.
data.phoneNumberstringThe E.164 number. The console UI reads this field.
data.alreadyExistsbooleantrue when an existing number was returned and nothing was bought.
data.phoneNumberSidstringCarrier id of the number.
data.providerstringtwilio.
data.countrystringCountry of the number.
data.areaCodenullAlways null on this path, because no area code is sent.
data.callProvider, webhookOwner, webhookUrl, vapiPhoneNumberIdstring or nullWhere incoming calls are routed.
data.messagingServiceSidstring or nullMessaging service the number was attached to.
data.enterpriseId, teamId, teamAgentMappingIdstringEcho of the scope.

Errors

StatusReasonWhen it happens
400Message from the agent backendNo number available (No available phone numbers found in US); enterpriseId does not match teamAgentMappingId; teamId does not match teamAgentMappingId; Active teamAgentMapping not found for ....
400Missing inputenterpriseId, teamId or teamAgentMappingId is missing. The framework rejects the call. The body for this case is not documented.
401Invalid tokenMissing or rejected token.
403Your session is not scoped to an enterprise ...The token carries no dealer group or no user id.
403You cannot purchase a phone number for another enterprise.The body's enterpriseId is not the token's dealer group.
404That rooftop does not exist on your enterprise.The rooftop is not found, or belongs to another dealer group.
408Request timeoutThe console could not reach the identity service to check the token.
409That rooftop is deactivated ...The rooftop is inactive.
409A phone number request for this agent is already in progress ...Another request for the same agent holds the lock.
424Could not verify the rooftop right now.The rooftop lookup failed.
424Phone number provisioning is temporarily unavailable.The lock store is unavailable, so the console refuses to buy.
424The phone number request did not complete in time ...No answer from the agent backend within 30 seconds. A number may have been bought.
429Too many requestsMore than 5 calls this hour for the dealer group or the user, or the limit store is unavailable.
500Could not provision a phone number right now.The agent backend returned a 5xx, for example when the carrier purchase failed.

What happens next

  • On success the console UI shows data.phoneNumber. It then calls Mark a task done with taskName: "Assign Number" and the tab's segmentName. That call is not awaited, and its failure is not shown.
  • The console UI also starts the receptionist trial clock. It does this on every tab, not only the receptionist.
  • Read the number back from List agents. That is the record the rest of the console uses.

Did this page help you?