curl --request POST \
--url https://api.isnap.ai/v1/lines/{id}/transfer-ownership \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"to_user_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"preserve_device_session": true
}
'import requests
url = "https://api.isnap.ai/v1/lines/{id}/transfer-ownership"
payload = {
"to_user_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"preserve_device_session": True
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
to_user_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
preserve_device_session: true
})
};
fetch('https://api.isnap.ai/v1/lines/{id}/transfer-ownership', 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.isnap.ai/v1/lines/{id}/transfer-ownership",
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([
'to_user_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'preserve_device_session' => true
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"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.isnap.ai/v1/lines/{id}/transfer-ownership"
payload := strings.NewReader("{\n \"to_user_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"preserve_device_session\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.isnap.ai/v1/lines/{id}/transfer-ownership")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"to_user_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"preserve_device_session\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.isnap.ai/v1/lines/{id}/transfer-ownership")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"to_user_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"preserve_device_session\": true\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"id": "<string>",
"phone_number": "<string>",
"area_code": "<string>",
"country_code": "<string>",
"state": "<string>",
"state_name": "<string>",
"billing_tier": "rental_iphone",
"byod": true,
"inbound_only": true,
"status": "<string>",
"monthly_price": 1,
"stripe_subscription_id": "<string>",
"activated_at": "<string>",
"expires_at": "<string>",
"anniversary_at": "<string>",
"cancel_at": "<string>",
"billing_anchor_at": "<string>",
"next_anchor_at": "<string>",
"pending_variant": {
"inbound_only": true,
"effective_at": "<string>"
},
"created_at": "<string>",
"metadata": {},
"test_line": true,
"shared": true,
"capabilities": "<unknown>",
"fulfillment_status": "<string>"
},
"trace_id": "<string>",
"request_id": "<string>"
}{
"success": false,
"data": "<unknown>",
"error": {
"status": 123,
"code": "<string>",
"message": "<string>",
"retry_after": 123,
"retry_at": "<string>",
"issues": [
{
"path": [
"<string>"
],
"message": "<string>",
"code": "<string>",
"min": 123,
"max": 123
}
]
},
"trace_id": "<string>",
"request_id": "<string>"
}{
"success": false,
"data": "<unknown>",
"error": {
"status": 123,
"code": "<string>",
"message": "<string>",
"retry_after": 123,
"retry_at": "<string>",
"issues": [
{
"path": [
"<string>"
],
"message": "<string>",
"code": "<string>",
"min": 123,
"max": 123
}
]
},
"trace_id": "<string>",
"request_id": "<string>"
}{
"success": false,
"data": "<unknown>",
"error": {
"status": 123,
"code": "<string>",
"message": "<string>",
"retry_after": 123,
"retry_at": "<string>",
"issues": [
{
"path": [
"<string>"
],
"message": "<string>",
"code": "<string>",
"min": 123,
"max": 123
}
]
},
"trace_id": "<string>",
"request_id": "<string>"
}{
"success": false,
"data": "<unknown>",
"error": {
"status": 123,
"code": "<string>",
"message": "<string>",
"retry_after": 123,
"retry_at": "<string>",
"issues": [
{
"path": [
"<string>"
],
"message": "<string>",
"code": "<string>",
"min": 123,
"max": 123
}
]
},
"trace_id": "<string>",
"request_id": "<string>"
}{
"success": false,
"data": "<unknown>",
"error": {
"status": 123,
"code": "<string>",
"message": "<string>",
"retry_after": 123,
"retry_at": "<string>",
"issues": [
{
"path": [
"<string>"
],
"message": "<string>",
"code": "<string>",
"min": 123,
"max": 123
}
]
},
"trace_id": "<string>",
"request_id": "<string>"
}{
"success": false,
"data": "<unknown>",
"error": {
"status": 123,
"code": "<string>",
"message": "<string>",
"retry_after": 123,
"retry_at": "<string>",
"issues": [
{
"path": [
"<string>"
],
"message": "<string>",
"code": "<string>",
"min": 123,
"max": 123
}
]
},
"trace_id": "<string>",
"request_id": "<string>"
}{
"success": false,
"data": "<unknown>",
"error": {
"status": 123,
"code": "<string>",
"message": "<string>",
"retry_after": 123,
"retry_at": "<string>",
"issues": [
{
"path": [
"<string>"
],
"message": "<string>",
"code": "<string>",
"min": 123,
"max": 123
}
]
},
"trace_id": "<string>",
"request_id": "<string>"
}Transfer a line to another account
Moves a line you own to another iSnap account, immediately and without the acceptance of that account.
curl --request POST \
--url https://api.isnap.ai/v1/lines/{id}/transfer-ownership \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"to_user_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"preserve_device_session": true
}
'import requests
url = "https://api.isnap.ai/v1/lines/{id}/transfer-ownership"
payload = {
"to_user_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"preserve_device_session": True
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
to_user_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
preserve_device_session: true
})
};
fetch('https://api.isnap.ai/v1/lines/{id}/transfer-ownership', 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.isnap.ai/v1/lines/{id}/transfer-ownership",
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([
'to_user_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'preserve_device_session' => true
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"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.isnap.ai/v1/lines/{id}/transfer-ownership"
payload := strings.NewReader("{\n \"to_user_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"preserve_device_session\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.isnap.ai/v1/lines/{id}/transfer-ownership")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"to_user_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"preserve_device_session\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.isnap.ai/v1/lines/{id}/transfer-ownership")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"to_user_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"preserve_device_session\": true\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"id": "<string>",
"phone_number": "<string>",
"area_code": "<string>",
"country_code": "<string>",
"state": "<string>",
"state_name": "<string>",
"billing_tier": "rental_iphone",
"byod": true,
"inbound_only": true,
"status": "<string>",
"monthly_price": 1,
"stripe_subscription_id": "<string>",
"activated_at": "<string>",
"expires_at": "<string>",
"anniversary_at": "<string>",
"cancel_at": "<string>",
"billing_anchor_at": "<string>",
"next_anchor_at": "<string>",
"pending_variant": {
"inbound_only": true,
"effective_at": "<string>"
},
"created_at": "<string>",
"metadata": {},
"test_line": true,
"shared": true,
"capabilities": "<unknown>",
"fulfillment_status": "<string>"
},
"trace_id": "<string>",
"request_id": "<string>"
}{
"success": false,
"data": "<unknown>",
"error": {
"status": 123,
"code": "<string>",
"message": "<string>",
"retry_after": 123,
"retry_at": "<string>",
"issues": [
{
"path": [
"<string>"
],
"message": "<string>",
"code": "<string>",
"min": 123,
"max": 123
}
]
},
"trace_id": "<string>",
"request_id": "<string>"
}{
"success": false,
"data": "<unknown>",
"error": {
"status": 123,
"code": "<string>",
"message": "<string>",
"retry_after": 123,
"retry_at": "<string>",
"issues": [
{
"path": [
"<string>"
],
"message": "<string>",
"code": "<string>",
"min": 123,
"max": 123
}
]
},
"trace_id": "<string>",
"request_id": "<string>"
}{
"success": false,
"data": "<unknown>",
"error": {
"status": 123,
"code": "<string>",
"message": "<string>",
"retry_after": 123,
"retry_at": "<string>",
"issues": [
{
"path": [
"<string>"
],
"message": "<string>",
"code": "<string>",
"min": 123,
"max": 123
}
]
},
"trace_id": "<string>",
"request_id": "<string>"
}{
"success": false,
"data": "<unknown>",
"error": {
"status": 123,
"code": "<string>",
"message": "<string>",
"retry_after": 123,
"retry_at": "<string>",
"issues": [
{
"path": [
"<string>"
],
"message": "<string>",
"code": "<string>",
"min": 123,
"max": 123
}
]
},
"trace_id": "<string>",
"request_id": "<string>"
}{
"success": false,
"data": "<unknown>",
"error": {
"status": 123,
"code": "<string>",
"message": "<string>",
"retry_after": 123,
"retry_at": "<string>",
"issues": [
{
"path": [
"<string>"
],
"message": "<string>",
"code": "<string>",
"min": 123,
"max": 123
}
]
},
"trace_id": "<string>",
"request_id": "<string>"
}{
"success": false,
"data": "<unknown>",
"error": {
"status": 123,
"code": "<string>",
"message": "<string>",
"retry_after": 123,
"retry_at": "<string>",
"issues": [
{
"path": [
"<string>"
],
"message": "<string>",
"code": "<string>",
"min": 123,
"max": 123
}
]
},
"trace_id": "<string>",
"request_id": "<string>"
}{
"success": false,
"data": "<unknown>",
"error": {
"status": 123,
"code": "<string>",
"message": "<string>",
"retry_after": 123,
"retry_at": "<string>",
"issues": [
{
"path": [
"<string>"
],
"message": "<string>",
"code": "<string>",
"min": 123,
"max": 123
}
]
},
"trace_id": "<string>",
"request_id": "<string>"
}- Credential: an API key of the owner of the line. The receiving account is not asked to accept, and it can be charged immediately: read Transfer before you call this operation.
- Line-scoped keys: a line-scoped key gets
403 forbiddenunless the line is in its list. - Test keys: a transfer sent with an
isnap_test_account key moves the real line, with the same effect on billing: see Test keys. Idempotency-Key: not honored. After a transfer, the line is not yours, and a second call returns404 not_found.- Events: none, to either account. See What events do not announce.
to_user_id: the UUID of the receiving account. The API has no operation that returns it. Ask support@isnap.ai for the UUID of the receiving account.- Chats: the line’s chats go with it. The receiving account can then receive your inbound messages of those chats that were not marked read and the events about your earlier messages: export what you need first, see A chat is never deleted.
Errors
| Status | error.code | When |
|---|---|---|
| 400 | invalid_recipient | to_user_id is not an iSnap account. |
| 403 | forbidden | The request uses a line-scoped key, and the line is not in its list. |
| 404 | not_found | No line has this id, or you do not own the line. |
| 409 | line_recipient_not_wholesale | The line is a shared line, a test line or a dedicated pool line, and the receiving account is not a wholesale partner. |
| 409 | android_rental_not_purchasable | The line is an active rental_android line, and the receiving account is not a wholesale partner. |
| 409 | recipient_no_payment_method | The receiving account has no payment method on file. It saves a card in the iSnap dashboard: see Accounts. |
| 409 | payment_failed | The payment method of the receiving account was declined. Nothing moved. |
| 409 | subscription_cancel_failed | Your per-line subscription of the line could not be canceled, and the line did not move. A direct receiving account can already have been charged: see Transfer. |
| 409 | transfer_conflict | The line left your account during the call, and it did not move. A direct receiving account can already have been charged, and your per-line subscription of the line, when it had one, is already canceled, with a prorated credit. See Transfer. |
| 409 | line_on_rented_macos_session, line_takes_no_macos_session | The hosted macOS session of the line does not fit the next owner. Only iSnap can resolve it: write to support@isnap.ai with the trace_id and request_id of the response. When that session changed during the call, these codes can follow the same billing steps as transfer_conflict, and a line that carried your per-line subscription then leaves your account. See Transfer. |
Authorizations
An API key created in the iSnap dashboard, or a trial key, sent as Authorization: Bearer <key>. An API key starts with isnap_live_ or isnap_test_; both act on the same account, lines and billing. A trial key acts on its trial only.
Path Parameters
Id of a line: line_ followed by 25 letters or digits.
^line_[0-9A-Za-z]{25}$Body
The account that receives the line, and what happens to the device sessions of the line.
UUID of the iSnap account that receives the line. An unknown account returns 400 invalid_recipient.
Defaults to true: the device of the line stays connected and the line keeps working for the new owner. false revokes the device sessions of the line, so the device must be paired again.
Response
The transferred line.
Always true on a success response.
true A line. billing_tier, byod, shared, test_line and inbound_only tell the kinds of line apart: a rented line (two-way or inbound-only), a BYOD line, a shared line, a test line.
Show child attributes
Show child attributes
Trace id of the request that produced this response: 32 lowercase hexadecimal characters. Quote it when you report a problem to iSnap.
Id of the request that produced this response: req_ followed by 25 letters or digits.