POST
/subscribe
Subscribe to a persistent phone number
Description
Pay $1800/year via x402 (USDC on Base) or MPP to acquire a persistent US phone number bound to your wallet address. Re-paying with the same wallet renews and keeps the same number — the response will set `renewed: true`.
A bare `POST /subscribe` (no payment header) returns `HTTP 402` with a payment challenge in the body listing every accepted scheme + asset. **Always read the challenge — don't hardcode amounts or addresses**. Production settles in USDC on Base mainnet.
Important: Your wallet address is your permanent account identity for this service. If you lose access to the wallet that paid for the subscription, you cannot recover your phone number or your remaining subscription time. Do not use ephemeral or per-session wallets. Recovery via signature requires the original wallet's private key.
Authentication
None. Public endpoint, no auth required.
Code samples
Pick your runtime. Every sample is in the page source — switching tabs is for your eyes.
curl https://agentnumber.really.com/subscribe \
--request POST \
--header 'X-PAYMENT: <X-PAYMENT>' \
--header 'Authorization: <Authorization>'interface SubscribeResponse {
token: string;
number: string;
expires_at: string;
renewed: boolean;
}
const response = await fetch('https://agentnumber.really.com/subscribe', {
method: 'POST',
headers: {
'X-PAYMENT': '<X-PAYMENT>',
Authorization: '<Authorization>'
}
});
if (!response.ok) {
throw new Error(`subscribe to a persistent phone number failed: ${response.status}`);
}
const data = (await response.json()) as SubscribeResponse;
requests.post("https://agentnumber.really.com/subscribe",
headers={
"X-PAYMENT": "<X-PAYMENT>",
"Authorization": "<Authorization>"
}
)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
requestUrl := "https://agentnumber.really.com/subscribe"
req, _ := http.NewRequest("POST", requestUrl, nil)
req.Header.Add("X-PAYMENT", "<X-PAYMENT>")
req.Header.Add("Authorization", "<Authorization>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}fetch('https://agentnumber.really.com/subscribe', {
method: 'POST',
headers: {
'X-PAYMENT': '<X-PAYMENT>',
Authorization: '<Authorization>'
}
})import { request } from 'undici'
const { statusCode, body } = await request('https://agentnumber.really.com/subscribe', {
method: 'POST',
headers: {
'X-PAYMENT': '<X-PAYMENT>',
Authorization: '<Authorization>'
}
})require 'uri'
require 'net/http'
url = URI("https://agentnumber.really.com/subscribe")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-PAYMENT"] = '<X-PAYMENT>'
request["Authorization"] = '<Authorization>'
response = http.request(request)
puts response.read_bodyimport Foundation
var request = URLRequest(url: URL(string: "https://agentnumber.really.com/subscribe")!)
request.httpMethod = "POST"
request.setValue("<X-PAYMENT>", forHTTPHeaderField: "X-PAYMENT")
request.setValue("<Authorization>", forHTTPHeaderField: "Authorization")
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse,
200..<300 ~= httpResponse.statusCode else {
throw URLError(.badServerResponse)
}
print(String(data: data, encoding: .utf8) ?? "")val client = OkHttpClient()
val request = Request.Builder()
.url("https://agentnumber.really.com/subscribe")
.post(null)
.addHeader("X-PAYMENT", "<X-PAYMENT>")
.addHeader("Authorization", "<Authorization>")
.build()
val response = client.newCall(request).execute()POST /subscribe HTTP/1.1
Host: agentnumber.really.com
X-PAYMENT: <X-PAYMENT>
Authorization: <Authorization>
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://agentnumber.really.com/subscribe"))
.header("X-PAYMENT", "<X-PAYMENT>")
.header("Authorization", "<Authorization>")
.method("POST", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());#import <Foundation/Foundation.h>
NSDictionary *headers = @{ @"X-PAYMENT": @"<X-PAYMENT>",
@"Authorization": @"<Authorization>" };
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://agentnumber.really.com/subscribe"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
[request setHTTPMethod:@"POST"];
[request setAllHTTPHeaderFields:headers];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"%@", error);
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
NSLog(@"%@", httpResponse);
}
}];
[dataTask resume];using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://agentnumber.really.com/subscribe");
request.Headers.TryAddWithoutValidation("X-PAYMENT", "<X-PAYMENT>");
using var response = await client.SendAsync(request);#include <curl/curl.h>
int main(void) {
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL *curl = curl_easy_init();
if (!curl) {
curl_global_cleanup();
return 1;
}
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_URL, "https://agentnumber.really.com/subscribe");
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "X-PAYMENT: <X-PAYMENT>");
headers = curl_slist_append(headers, "Authorization: <Authorization>");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
CURLcode res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
curl_slist_free_all(headers);
curl_global_cleanup();
return (int)res;
}import 'package:http/http.dart' as http;
void main() async {
final headers = <String,String>{
'X-PAYMENT': '<X-PAYMENT>',
'Authorization': '<Authorization>',
};
final response = await http.post(Uri.parse('https://agentnumber.really.com/subscribe'), headers: headers);
print(response.body);
}let client = reqwest::Client::new();
let request = client
.post("https://agentnumber.really.com/subscribe")
.header("X-PAYMENT", "<X-PAYMENT>")
.header("Authorization", "<Authorization>");
let response = request.send().await?;$ch = curl_init("https://agentnumber.really.com/subscribe");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-PAYMENT: <X-PAYMENT>', 'Authorization: <Authorization>']);
curl_exec($ch);
curl_close($ch);Headers
| Name | Type | Description |
|---|---|---|
X-PAYMENT |
string |
Base64-encoded x402 EIP-3009 transferWithAuthorization signature. Present after the agent has parsed the 402 challenge and signed. |
Authorization |
string |
MPP path: `Payment <base64-credential>` carrying a Tempo TIP-20 charge. Mutually exclusive with `X-PAYMENT`. |
Responses
200 Subscription confirmed (new or renewed).
{
"token": "an_123xyz123xyz123xyz123xyz123xyz",
"number": "+15555550123",
"expires_at": "2027-04-30T18:24:01.000Z",
"renewed": false
}
402 Payment required. Body lists every accepted scheme + asset for the current environment. Sign per `accepts[]` and retry with `X-PAYMENT` or `Authorization: Payment`.
{
"x402Version": 2,
"error": "X-PAYMENT header is required",
"accepts": [
{
"scheme": "exact",
"network": "base",
"amount": "1800000000",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"payTo": "0x0000000000000000000000000000000000000000",
"maxTimeoutSeconds": 300,
"extra": {
"name": "USDC",
"version": "2"
}
}
]
}
503 Number pool exhausted. Check `/availability` and join `/waitlist`.
{
"error": "pool_exhausted",
"message": "No phone numbers currently available.",
"check_availability": "/availability",
"join_waitlist": "/waitlist",
"available": 0
}