curl --request POST \
--url https://api.withallo.com/v2/api/partner/accounts/{id}/members \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"email": "[email protected]",
"name": "Paul Martin",
"personal_mobile": "+33612345679",
"role": "MEMBER",
"number_preference": {
"country": "FR",
"esim": true
}
}
'import requests
url = "https://api.withallo.com/v2/api/partner/accounts/{id}/members"
payload = {
"email": "[email protected]",
"name": "Paul Martin",
"personal_mobile": "+33612345679",
"role": "MEMBER",
"number_preference": {
"country": "FR",
"esim": True
}
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
email: '[email protected]',
name: 'Paul Martin',
personal_mobile: '+33612345679',
role: 'MEMBER',
number_preference: {country: 'FR', esim: true}
})
};
fetch('https://api.withallo.com/v2/api/partner/accounts/{id}/members', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.withallo.com/v2/api/partner/accounts/{id}/members",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'email' => '[email protected]',
'name' => 'Paul Martin',
'personal_mobile' => '+33612345679',
'role' => 'MEMBER',
'number_preference' => [
'country' => 'FR',
'esim' => true
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.withallo.com/v2/api/partner/accounts/{id}/members"
payload := strings.NewReader("{\n \"email\": \"[email protected]\",\n \"name\": \"Paul Martin\",\n \"personal_mobile\": \"+33612345679\",\n \"role\": \"MEMBER\",\n \"number_preference\": {\n \"country\": \"FR\",\n \"esim\": true\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.withallo.com/v2/api/partner/accounts/{id}/members")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"email\": \"[email protected]\",\n \"name\": \"Paul Martin\",\n \"personal_mobile\": \"+33612345679\",\n \"role\": \"MEMBER\",\n \"number_preference\": {\n \"country\": \"FR\",\n \"esim\": true\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.withallo.com/v2/api/partner/accounts/{id}/members")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"email\": \"[email protected]\",\n \"name\": \"Paul Martin\",\n \"personal_mobile\": \"+33612345679\",\n \"role\": \"MEMBER\",\n \"number_preference\": {\n \"country\": \"FR\",\n \"esim\": true\n }\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "usr-8C1B2E7F4A9D3C6B0E5F1A2D7C4B9E3F6A0D8C21",
"account_id": "usr-575966AF3661061265263C58882BC409D2A427B8",
"email": "[email protected]",
"name": "Paul Martin",
"role": "MEMBER",
"phone_numbers": [
"+33745805111"
],
"status": "ACTIVE",
"activated": false
}
}{
"error": {}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"retry_after_seconds": 123
}
}{
"error": {}
}{
"error": {}
}{
"error": {}
}{
"error": {}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"retry_after_seconds": 123
}
}{
"error": {}
}Add member
Adds a member to one of your accounts, with a phone number of their own. The member takes a seat the account already pays for and no one uses, or one more seat on the account’s subscription, which you pay: Allo draws on your prepaid credit first, then charges your card on file for the rest. The seat includes the member’s number, so the number is not billed on top. Allo sends the member no invitation email. Allo checks that a number is available before charging anything. Requires the PARTNER scope.
curl --request POST \
--url https://api.withallo.com/v2/api/partner/accounts/{id}/members \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"email": "[email protected]",
"name": "Paul Martin",
"personal_mobile": "+33612345679",
"role": "MEMBER",
"number_preference": {
"country": "FR",
"esim": true
}
}
'import requests
url = "https://api.withallo.com/v2/api/partner/accounts/{id}/members"
payload = {
"email": "[email protected]",
"name": "Paul Martin",
"personal_mobile": "+33612345679",
"role": "MEMBER",
"number_preference": {
"country": "FR",
"esim": True
}
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
email: '[email protected]',
name: 'Paul Martin',
personal_mobile: '+33612345679',
role: 'MEMBER',
number_preference: {country: 'FR', esim: true}
})
};
fetch('https://api.withallo.com/v2/api/partner/accounts/{id}/members', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.withallo.com/v2/api/partner/accounts/{id}/members",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'email' => '[email protected]',
'name' => 'Paul Martin',
'personal_mobile' => '+33612345679',
'role' => 'MEMBER',
'number_preference' => [
'country' => 'FR',
'esim' => true
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.withallo.com/v2/api/partner/accounts/{id}/members"
payload := strings.NewReader("{\n \"email\": \"[email protected]\",\n \"name\": \"Paul Martin\",\n \"personal_mobile\": \"+33612345679\",\n \"role\": \"MEMBER\",\n \"number_preference\": {\n \"country\": \"FR\",\n \"esim\": true\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.withallo.com/v2/api/partner/accounts/{id}/members")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"email\": \"[email protected]\",\n \"name\": \"Paul Martin\",\n \"personal_mobile\": \"+33612345679\",\n \"role\": \"MEMBER\",\n \"number_preference\": {\n \"country\": \"FR\",\n \"esim\": true\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.withallo.com/v2/api/partner/accounts/{id}/members")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"email\": \"[email protected]\",\n \"name\": \"Paul Martin\",\n \"personal_mobile\": \"+33612345679\",\n \"role\": \"MEMBER\",\n \"number_preference\": {\n \"country\": \"FR\",\n \"esim\": true\n }\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "usr-8C1B2E7F4A9D3C6B0E5F1A2D7C4B9E3F6A0D8C21",
"account_id": "usr-575966AF3661061265263C58882BC409D2A427B8",
"email": "[email protected]",
"name": "Paul Martin",
"role": "MEMBER",
"phone_numbers": [
"+33745805111"
],
"status": "ACTIVE",
"activated": false
}
}{
"error": {}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"retry_after_seconds": 123
}
}{
"error": {}
}{
"error": {}
}{
"error": {}
}{
"error": {}
}{
"error": {
"type": "<string>",
"code": "<string>",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"retry_after_seconds": 123
}
}{
"error": {}
}PARTNERid you need to order the member’s eSIM.
Request
emailis required and becomes the member’s login.nameis required.personal_mobileis optional, in E.164 format, for example+33612345679. A number Allo cannot read fails withINVALID_PHONE_NUMBER.roleis optional:ADMIN,MANAGERorMEMBER,MEMBERby default. Any other value fails withINVALID_MEMBER_ROLE.number_preferenceis required: the member’s number, with the same fields as on Create account.number_preference.countryis required. Setnumber_preference.esimtotrueto give the member a French mobile number that can carry an eSIM.- If the email or the personal mobile already belongs to an Allo account, the request fails with
409 PARTNER_ACCOUNT_ALREADY_EXISTS, andparamnames the field.
{id} is the account id returned by Create account. An account your API key did not create, or one already deactivated, returns 404 PARTNER_ACCOUNT_NOT_FOUND.
What Allo does
- Allo creates the member in the account’s workspace and assigns the member’s number.
- Allo sends the member no invitation email. You onboard the member yourself. The member signs in to Allo with the email (or the personal mobile) you sent, and
activatedturnstrueonce they sign in on a device. - The member takes a seat on the account’s subscription. The seat includes the member’s number, so the number is not billed on top.
Billing
- If the account already pays for a seat that no one uses, the member takes it and nothing is charged.
- Otherwise Allo adds one seat to the account’s subscription, which you pay, and charges the rest of the current billing period now, with the subscription’s discount applied. Allo draws on your prepaid credit first, then charges your card on file for the rest. Allo never charges your customer.
- Allo checks the email, the personal mobile and the number before charging anything. If no number matches, the request fails with
409 NO_NUMBER_AVAILABLEand nothing is charged. - If your prepaid credit does not cover the seat and you have no card on file, the request fails with
402 PARTNER_CREDIT_INSUFFICIENTand nothing is created. A declined card fails with402 PARTNER_BILLING_FAILED. - If the member’s number cannot be set up after the charge, Allo removes the member and takes the seat back off the subscription.
Idempotency-Key. If a request times out, check List members before you retry: once the member exists, a retry with the same email fails with PARTNER_ACCOUNT_ALREADY_EXISTS.
How to give the member an eSIM
Add the member with an eSIM number
number_preference: {"country": "FR", "esim": true}. The member gets a French mobile number that can carry an eSIM, listed in phone_numbers.Order the eSIM for the member
POST /v2/api/partner/accounts/{account_id}/esims). Send the member’s number as phone_number and the member’s id as holder_id. The eSIM is then registered to the member, not to the account.Deliver the eSIM
partner.esim.ready, then send the member the code from Get eSIM activation code.Errors
| Code | What it means |
|---|---|
REGULATORY_VERIFICATION_REQUIRED | A number in this country needs the account’s regulatory verification first. Nothing is charged. |
PARTNER_ACCOUNT_BUSY | Another number or member is being added to this account, or this email is being added elsewhere, right now. Always retryable: true: retry in a few seconds. |
PARTNER_ACCOUNT_DEACTIVATING | The account is being deactivated at the end of its billing period, so it takes no more members. |
PARTNER_ACCOUNT_SUBSCRIPTION_CONFLICT | The account’s subscription cannot be billed right now. When retryable is true, retry in a few minutes. Otherwise write to [email protected]. |
PARTNER_SUBSCRIPTION_NOT_BILLABLE | The account has no subscription Allo can bill (402). |
PARTNER_BILLING_UNAVAILABLE | Billing is temporarily unavailable (500). Retry in a few seconds. |
PARTNER_NUMBER_SETUP_FAILED | The member’s number could not be set up (500). The member and the charge were removed. Write to [email protected]. |
PARTNER_NUMBER_KEPT | The number was assigned but its setup did not complete (500). It stays on the account with the member’s seat. Do not retry: write to [email protected] with the number. |
Authorizations
Path Parameters
The account id returned by Create account (usr-*).
Body
Becomes the member's login. It must not belong to an Allo account yet.
"Paul Martin"
The member's number.
Show child attributes
Show child attributes
Optional, E.164. The member's own mobile. It must not belong to an Allo account yet.
"+33612345679"
Optional, default MEMBER. The member's role in the account's workspace.
ADMIN, MANAGER, MEMBER "MEMBER"
Response
Member added
Show child attributes
Show child attributes
Was this page helpful?