Create Account
curl --request POST \
--url https://api.fifteenth.com/v1beta/accounts \
--header 'Authorization: <authorization>' \
--header 'Content-Type: <content-type>' \
--data '
{
"email": "<string>",
"first_name": "<string>",
"last_name": "<string>",
"spouse": {
"spouse.email": "<string>",
"spouse.first_name": "<string>",
"spouse.last_name": "<string>",
"spouse.send_invitation": true
}
}
'import requests
url = "https://api.fifteenth.com/v1beta/accounts"
payload = {
"email": "<string>",
"first_name": "<string>",
"last_name": "<string>",
"spouse": {
"spouse.email": "<string>",
"spouse.first_name": "<string>",
"spouse.last_name": "<string>",
"spouse.send_invitation": True
}
}
headers = {
"Authorization": "<authorization>",
"Content-Type": "<content-type>"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': '<content-type>'},
body: JSON.stringify({
email: '<string>',
first_name: '<string>',
last_name: '<string>',
spouse: {
'spouse.email': '<string>',
'spouse.first_name': '<string>',
'spouse.last_name': '<string>',
'spouse.send_invitation': true
}
})
};
fetch('https://api.fifteenth.com/v1beta/accounts', 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.fifteenth.com/v1beta/accounts",
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' => '<string>',
'first_name' => '<string>',
'last_name' => '<string>',
'spouse' => [
'spouse.email' => '<string>',
'spouse.first_name' => '<string>',
'spouse.last_name' => '<string>',
'spouse.send_invitation' => true
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: <content-type>"
],
]);
$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.fifteenth.com/v1beta/accounts"
payload := strings.NewReader("{\n \"email\": \"<string>\",\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"spouse\": {\n \"spouse.email\": \"<string>\",\n \"spouse.first_name\": \"<string>\",\n \"spouse.last_name\": \"<string>\",\n \"spouse.send_invitation\": true\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
req.Header.Add("Content-Type", "<content-type>")
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.fifteenth.com/v1beta/accounts")
.header("Authorization", "<authorization>")
.header("Content-Type", "<content-type>")
.body("{\n \"email\": \"<string>\",\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"spouse\": {\n \"spouse.email\": \"<string>\",\n \"spouse.first_name\": \"<string>\",\n \"spouse.last_name\": \"<string>\",\n \"spouse.send_invitation\": true\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.fifteenth.com/v1beta/accounts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = '<content-type>'
request.body = "{\n \"email\": \"<string>\",\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"spouse\": {\n \"spouse.email\": \"<string>\",\n \"spouse.first_name\": \"<string>\",\n \"spouse.last_name\": \"<string>\",\n \"spouse.send_invitation\": true\n }\n}"
response = http.request(request)
puts response.read_body{
"id": 123,
"status": "<string>",
"login_link": "<string>",
"login_link_expires_at": "<string>",
"spouse": {
"spouse.id": 123,
"spouse.email": "<string>",
"spouse.first_name": "<string>",
"spouse.last_name": "<string>",
"spouse.login_link": "<string>",
"spouse.login_link_expires_at": "<string>",
"spouse.status": "<string>"
},
"created_at": "<string>",
"400 Bad Request": {},
"409 Conflict": {},
"429 Too Many Requests": {}
}Accounts
Create Account
Create a new tax preparation account for a client with custom branding and authentication
POST
/
v1beta
/
accounts
Create Account
curl --request POST \
--url https://api.fifteenth.com/v1beta/accounts \
--header 'Authorization: <authorization>' \
--header 'Content-Type: <content-type>' \
--data '
{
"email": "<string>",
"first_name": "<string>",
"last_name": "<string>",
"spouse": {
"spouse.email": "<string>",
"spouse.first_name": "<string>",
"spouse.last_name": "<string>",
"spouse.send_invitation": true
}
}
'import requests
url = "https://api.fifteenth.com/v1beta/accounts"
payload = {
"email": "<string>",
"first_name": "<string>",
"last_name": "<string>",
"spouse": {
"spouse.email": "<string>",
"spouse.first_name": "<string>",
"spouse.last_name": "<string>",
"spouse.send_invitation": True
}
}
headers = {
"Authorization": "<authorization>",
"Content-Type": "<content-type>"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': '<content-type>'},
body: JSON.stringify({
email: '<string>',
first_name: '<string>',
last_name: '<string>',
spouse: {
'spouse.email': '<string>',
'spouse.first_name': '<string>',
'spouse.last_name': '<string>',
'spouse.send_invitation': true
}
})
};
fetch('https://api.fifteenth.com/v1beta/accounts', 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.fifteenth.com/v1beta/accounts",
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' => '<string>',
'first_name' => '<string>',
'last_name' => '<string>',
'spouse' => [
'spouse.email' => '<string>',
'spouse.first_name' => '<string>',
'spouse.last_name' => '<string>',
'spouse.send_invitation' => true
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: <content-type>"
],
]);
$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.fifteenth.com/v1beta/accounts"
payload := strings.NewReader("{\n \"email\": \"<string>\",\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"spouse\": {\n \"spouse.email\": \"<string>\",\n \"spouse.first_name\": \"<string>\",\n \"spouse.last_name\": \"<string>\",\n \"spouse.send_invitation\": true\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
req.Header.Add("Content-Type", "<content-type>")
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.fifteenth.com/v1beta/accounts")
.header("Authorization", "<authorization>")
.header("Content-Type", "<content-type>")
.body("{\n \"email\": \"<string>\",\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"spouse\": {\n \"spouse.email\": \"<string>\",\n \"spouse.first_name\": \"<string>\",\n \"spouse.last_name\": \"<string>\",\n \"spouse.send_invitation\": true\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.fifteenth.com/v1beta/accounts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = '<content-type>'
request.body = "{\n \"email\": \"<string>\",\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"spouse\": {\n \"spouse.email\": \"<string>\",\n \"spouse.first_name\": \"<string>\",\n \"spouse.last_name\": \"<string>\",\n \"spouse.send_invitation\": true\n }\n}"
response = http.request(request)
puts response.read_body{
"id": 123,
"status": "<string>",
"login_link": "<string>",
"login_link_expires_at": "<string>",
"spouse": {
"spouse.id": 123,
"spouse.email": "<string>",
"spouse.first_name": "<string>",
"spouse.last_name": "<string>",
"spouse.login_link": "<string>",
"spouse.login_link_expires_at": "<string>",
"spouse.status": "<string>"
},
"created_at": "<string>",
"400 Bad Request": {},
"409 Conflict": {},
"429 Too Many Requests": {}
}Overview
The Create Account endpoint allows you to onboard new clients to Fifteenth services. Each account is associated with your partner organization and includes unique login credentials, custom branding, and access to professional tax preparation services.Account creation returns a unique login link that expires in 7 days. This allows your clients to access their Fifteenth account without creating separate credentials.
Request
Headers
string
required
Bearer token with your Partner API key
string
required
Must be
application/jsonBody Parameters
string
required
Client’s primary email address for communication and account access.Validation: Must be valid email format
Example:
Example:
john.doe@example.comstring
required
Client’s first name as it appears on tax documents.Format: Max 50 characters
Example:
Example:
Johnstring
required
Client’s last name as it appears on tax documents.Format: Max 50 characters
Example:
Example:
Doeobject
Optional spouse information. If provided, the spouse will have full account access equivalent to the primary account holder.
Show spouse object
Show spouse object
string
required
Spouse’s email address for login and communications.
Validation: Must be valid email format, unique across Fifteenth
string
required
Spouse’s first name as it appears on tax documents.
Format: Max 50 characters
string
required
Spouse’s last name as it appears on tax documents.
Format: Max 50 characters
boolean
Whether to send an invitation email to the spouse.
Default:
trueResponse
Success Response
number
Unique Fifteenth account identifier.
string
Current account status. Always
active for newly created accounts.string
IMPORTANT: Unique, time-limited URL for client access to their Fifteenth account.This link:
- Expires in 7 days from creation
- Can only be used once for initial login
- Grants full access to the client’s account
- Should be securely transmitted to the client
string
ISO 8601 timestamp when the login link expires.
object
Spouse information and access details (if spouse was provided in request).
Show spouse object
Show spouse object
number
Unique spouse user identifier.
string
Spouse’s email address.
string
Spouse’s first name.
string
Spouse’s last name.
string
Unique login link for spouse’s first-time access (if invitation sent).
string
Expiration timestamp for the spouse’s login link.
string
Spouse’s current status:
invited or pending.string
ISO 8601 timestamp when the account was created.
Examples
Basic Account Creation
import requests
url = "https://api.fifteenth.com/v1beta/accounts"
headers = {
"Authorization": "Bearer 15th_your_api_key_here",
"Content-Type": "application/json"
}
data = {
"email": "john.doe@example.com",
"first_name": "John",
"last_name": "Doe"
}
response = requests.post(url, headers=headers, json=data)
account = response.json()
print(f"Account created: {account['id']}")
print(f"Login link: {account['login_link']}")
print(f"Expires at: {account['login_link_expires_at']}")
const url = 'https://api.fifteenth.com/v1beta/accounts';
const headers = {
'Authorization': 'Bearer 15th_your_api_key_here',
'Content-Type': 'application/json'
};
const data = {
email: 'john.doe@example.com',
first_name: 'John',
last_name: 'Doe'
};
const response = await fetch(url, {
method: 'POST',
headers: headers,
body: JSON.stringify(data)
});
const account = await response.json();
console.log(`Account created: ${account.id}`);
console.log(`Login link: ${account.login_link}`);
console.log(`Expires at: ${account.login_link_expires_at}`);
curl -X POST "https://api.fifteenth.com/v1beta/accounts" \
-H "Authorization: Bearer 15th_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"email": "john.doe@example.com",
"first_name": "John",
"last_name": "Doe"
}'
Account with Spouse
data = {
"email": "john.doe@example.com",
"first_name": "John",
"last_name": "Doe",
"spouse": {
"email": "jane.doe@example.com",
"first_name": "Jane",
"last_name": "Doe",
"send_invitation": True
}
}
response = requests.post(url, headers=headers, json=data)
account = response.json()
print(f"Account created: {account['id']}")
print(f"Primary login: {account['login_link']}")
if account.get('spouse'):
print(f"Spouse login: {account['spouse']['login_link']}")
print(f"Spouse status: {account['spouse']['status']}")
const data = {
email: 'john.doe@example.com',
first_name: 'John',
last_name: 'Doe',
spouse: {
email: 'jane.doe@example.com',
first_name: 'Jane',
last_name: 'Doe',
send_invitation: true
}
};
const response = await fetch(url, {
method: 'POST',
headers: headers,
body: JSON.stringify(data)
});
const account = await response.json();
console.log(`Account created: ${account.id}`);
console.log(`Primary login: ${account.login_link}`);
if (account.spouse) {
console.log(`Spouse login: ${account.spouse.login_link}`);
console.log(`Spouse status: ${account.spouse.status}`);
}
curl -X POST "https://api.fifteenth.com/v1beta/accounts" \
-H "Authorization: Bearer 15th_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"email": "john.doe@example.com",
"first_name": "John",
"last_name": "Doe",
"spouse": {
"email": "jane.doe@example.com",
"first_name": "Jane",
"last_name": "Doe",
"send_invitation": true
}
}'
Response Examples
Successful Account Creation
Response
{
"id": 12345,
"email": "john.doe@example.com",
"first_name": "John",
"last_name": "Doe",
"status": "active",
"login_link": "https://app.fifteenth.com/auth/partner-login/tk_A7xM9pQ2vK8xLqR4S",
"login_link_expires_at": "2024-01-22T10:30:00Z",
"created_at": "2024-01-15T10:30:00Z"
}
Account with Spouse Response
Response (With Spouse)
{
"id": 67890,
"email": "john.doe@example.com",
"first_name": "John",
"last_name": "Doe",
"status": "active",
"login_link": "https://app.fifteenth.com/auth/partner-login/tk_P7sT0zQ2wU4oM7yN",
"login_link_expires_at": "2024-01-22T10:30:00Z",
"spouse": {
"id": 67891,
"email": "jane.doe@example.com",
"first_name": "Jane",
"last_name": "Doe",
"login_link": "https://app.fifteenth.com/auth/user-login/tk_R9uV2BS4yW6qO9AP",
"login_link_expires_at": "2024-01-22T10:30:00Z",
"status": "invited"
},
"created_at": "2024-01-15T10:30:00Z"
}
Error Responses
object
Invalid request data or missing required fields.
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request data",
"details": {
"email": ["Invalid email format"],
"tax_year": ["Must be between 2020 and 2025"]
}
}
}
object
Account with the same email already exists.
{
"error": {
"code": "DUPLICATE_EMAIL",
"message": "An account with this email already exists",
"details": {
"email": "john.doe@example.com",
"existing_account_id": 12345
}
}
}
object
Rate limit exceeded.
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Please retry after 60 seconds.",
"details": {
"limit": 100,
"window_seconds": 60,
"reset_at": "2024-01-15T10:31:00Z"
}
}
}
Usage Notes
Login Link Security
The login link provides full access to the client’s tax account. Handle it securely:
- Transmit via secure channels only (encrypted email, secure portal)
- Do not log or store login links in plain text
- Advise clients not to share the link
- Link expires automatically after 7 days
Email Management Best Practices
- Ensure email addresses are accurate and monitored
- Use unique email addresses for each account
- Consider using client’s primary business email
- Email will be used for account recovery and important notifications
Account Type Implications
| Account Type | Tax Forms | Typical Use Case |
|---|---|---|
individual | 1040, schedules | Personal tax returns |
business | 1120, 1120S, 1065, 1041 | Corporate, partnership, S-Corp returns |
trust_estate | 1041, 706 | Trust and estate tax planning |
Next Steps
After creating an account:- Send login link to client via secure communication
- Monitor account status using Retrieve Account
- Upload initial documents using Document Upload
- Track project progress using Project Status
Usage Notes
Spouse Functionality
When including spouse information during account creation:- Full Access: Spouses automatically receive full account access equivalent to the primary account holder
- Separate Login: Each spouse gets their own login link and credentials
- Invitation Control: Set
send_invitation: falseto add spouse without immediately sending access - One Spouse Only: Only one spouse per account is supported
- Joint Returns: Ideal for married filing jointly tax situations
Best Practices
Email Verification
Email Verification
Ensure both primary and spouse email addresses are correct, as they will receive sensitive tax information.
Account Types
Account Types
- Use
individualfor personal tax returns (1040) - Use
businessfor business entities - Include spouse information primarily for individual accounts
Login Management
Login Management
Both the primary account holder and spouse will receive separate login links that expire in 7 days. Use the Generate Login Link endpoint to create new links as needed.
Retrieve Account
Get account details and current status
Upload Documents
Upload tax documents for the account
Account Details
Retrieve complete account information
Generate Login Link
Generate new login links if needed