Business Entity Formation Workflow
Form new business entities through the SingleFile API. Choose between Manual Payload (full control, structured data) or Document-Based (upload existing docs, auto-extract fields).
How It Works
Your App SingleFile API State Authority
| | |
|--- GET /schemas ----------->| |
|<-- field requirements ------| |
| | |
|--- POST /orders ----------->| |
| (preview=true) | |
|<-- validation result -------| |
| | |
|--- POST /orders ----------->|---- files with state ------>|
|<-- order_id + status -------| |
| |<--- approval/rejection -----|
|<-- webhook event -----------| |
Choose Your Approach
| Manual Payload | Document-Based | |
|---|---|---|
| Best for | Automated systems, full control over every field | Existing docs, bulk processing, reduced data entry |
| Required fields | All fields mandatory | registered_agent and authorized_person_name auto-extracted |
| Setup time | 15-30 min | 10-20 min |
| Per formation | 2-5 min | 1-3 min |
| Processing | 1-3 business days | 1-3 business days + 5-15 min doc extraction |
Manual Payload Formation
Prerequisites
- Valid API access token
- Entity type and jurisdiction information
- Required business information (name, addresses, etc.)
Step 1: Organization Setup
First, check if an organization exists, or create one if needed:
ACCESS_TOKEN="your_bearer_token_here"
ORG_NAME="Acme Ventures LLC"
DOMAIN="acmeventures.com"
# List organizations to find by name
curl -s -X GET "https://api.demo.singlefile.io/external-api/v1/organizations" \
-H "Authorization: Bearer $ACCESS_TOKEN"
# Create organization if not found (replace org_xxx with ID from list or run create)
curl -s -X POST "https://api.demo.singlefile.io/external-api/v1/organization/create" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"'$ORG_NAME'","domain":"'$DOMAIN'","notes":"Auto-created for '$ORG_NAME' formation","send_all_state_notice":true,"invoice_only":false}'import requests
def get_or_create_organization(org_name, domain, access_token):
"""Get existing organization or create new one"""
# Try to find existing organization
response = requests.get(
"https://api.demo.singlefile.io/external-api/v1/organizations",
headers={"Authorization": f"Bearer {access_token}"}
)
if response.status_code == 200:
organizations = response.json()["data"]
for org in organizations:
if org["name"] == org_name:
print(f"Found existing organization: {org['id']}")
return org["id"]
# Create new organization if not found
org_data = {
"name": org_name,
"domain": domain,
"notes": f"Auto-created for {org_name} formation",
"send_all_state_notice": True,
"invoice_only": False
}
response = requests.post(
"https://api.demo.singlefile.io/external-api/v1/organization/create",
json=org_data,
headers={
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
)
if response.status_code == 201:
organization = response.json()["data"]
print(f"Created new organization: {organization['id']}")
return organization["id"]
else:
raise Exception(f"Failed to create organization: {response.status_code}")
# Get or create organization
ACCESS_TOKEN = "your_bearer_token_here"
organization_id = get_or_create_organization(
"Acme Ventures LLC",
"acmeventures.com",
ACCESS_TOKEN
)const BASE_URL = "https://api.demo.singlefile.io";
async function getOrCreateOrganization(orgName, domain, accessToken) {
const listRes = await fetch(`${BASE_URL}/external-api/v1/organizations`, {
headers: { Authorization: `Bearer ${accessToken}` }
});
if (listRes.ok) {
const { data } = await listRes.json();
const existing = data.find(org => org.name === orgName);
if (existing) {
console.log(`Found existing organization: ${existing.id}`);
return existing.id;
}
}
const orgData = {
name: orgName,
domain,
notes: `Auto-created for ${orgName} formation`,
send_all_state_notice: true,
invoice_only: false
};
const createRes = await fetch(`${BASE_URL}/external-api/v1/organization/create`, {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json"
},
body: JSON.stringify(orgData)
});
if (createRes.status === 201) {
const { data } = await createRes.json();
console.log(`Created new organization: ${data.id}`);
return data.id;
}
throw new Error(`Failed to create organization: ${createRes.status}`);
}
const ACCESS_TOKEN = "your_bearer_token_here";
const organizationId = await getOrCreateOrganization("Acme Ventures LLC", "acmeventures.com", ACCESS_TOKEN);package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
const baseURL = "https://api.demo.singlefile.io"
func getOrCreateOrganization(orgName, domain, accessToken string) (string, error) {
req, _ := http.NewRequest("GET", baseURL+"/external-api/v1/organizations", nil)
req.Header.Set("Authorization", "Bearer "+accessToken)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode == 200 {
var result struct {
Data []struct {
ID string `json:"id"`
Name string `json:"name"`
} `json:"data"`
}
json.NewDecoder(resp.Body).Decode(&result)
for _, org := range result.Data {
if org.Name == orgName {
fmt.Printf("Found existing organization: %s\n", org.ID)
return org.ID, nil
}
}
}
orgData := map[string]interface{}{
"name": orgName,
"domain": domain,
"notes": fmt.Sprintf("Auto-created for %s formation", orgName),
"send_all_state_notice": true,
"invoice_only": false,
}
body, _ := json.Marshal(orgData)
req, _ = http.NewRequest("POST", baseURL+"/external-api/v1/organization/create", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+accessToken)
req.Header.Set("Content-Type", "application/json")
resp, err = http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode == 201 {
var result struct {
Data struct {
ID string `json:"id"`
} `json:"data"`
}
json.NewDecoder(resp.Body).Decode(&result)
fmt.Printf("Created new organization: %s\n", result.Data.ID)
return result.Data.ID, nil
}
b, _ := io.ReadAll(resp.Body)
return "", fmt.Errorf("failed to create organization: %s", string(b))
}
func main() {
accessToken := "your_bearer_token_here"
orgID, err := getOrCreateOrganization("Acme Ventures LLC", "acmeventures.com", accessToken)
if err != nil {
panic(err)
}
_ = orgID
}using System.Net.Http;
using System.Text;
using System.Text.Json;
var baseUrl = "https://api.demo.singlefile.io";
async Task<string> GetOrCreateOrganizationAsync(string orgName, string domain, string accessToken)
{
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {accessToken}");
var listRes = await client.GetAsync($"{baseUrl}/external-api/v1/organizations");
if (listRes.IsSuccessStatusCode)
{
var json = await listRes.Content.ReadAsStringAsync();
var doc = JsonDocument.Parse(json);
foreach (var org in doc.RootElement.GetProperty("data").EnumerateArray())
{
if (org.GetProperty("name").GetString() == orgName)
{
Console.WriteLine($"Found existing organization: {org.GetProperty("id").GetString()}");
return org.GetProperty("id").GetString()!;
}
}
}
var orgData = new { name = orgName, domain = domain, notes = $"Auto-created for {orgName} formation", send_all_state_notice = true, invoice_only = false };
var content = new StringContent(JsonSerializer.Serialize(orgData), Encoding.UTF8, "application/json");
var createRes = await client.PostAsync($"{baseUrl}/external-api/v1/organization/create", content);
if (createRes.StatusCode == System.Net.HttpStatusCode.Created)
{
var createJson = await createRes.Content.ReadAsStringAsync();
var createDoc = JsonDocument.Parse(createJson);
var id = createDoc.RootElement.GetProperty("data").GetProperty("id").GetString();
Console.WriteLine($"Created new organization: {id}");
return id!;
}
throw new Exception($"Failed to create organization: {createRes.StatusCode}");
}
var accessToken = "your_bearer_token_here";
var organizationId = await GetOrCreateOrganizationAsync("Acme Ventures LLC", "acmeventures.com", accessToken);Step 2: Retrieve Formation Schema
Before creating a formation order, retrieve the schema that defines required fields and validation rules for your entity type and jurisdiction.
All parameter values are case insensitive. For example,
"LLC","llc", and"Llc"are all valid for theentity_typeparameter.
| Parameter | Description | Examples |
|---|---|---|
entity_type | Type of business entity | llc, corporation, limited partnership |
filing_type | Filing action | formation, foreign qualification |
jurisdiction | State for filing | delaware, california, texas |
ACCESS_TOKEN="your_bearer_token_here"
ENTITY_TYPE="llc"
JURISDICTION="delaware"
curl -s -X GET "https://api.demo.singlefile.io/external-api/v1/schemas?entity_type=$ENTITY_TYPE&filing_type=formation&jurisdiction=$JURISDICTION" \
-H "Authorization: Bearer $ACCESS_TOKEN"import requests
def get_schema(entity_type, filing_type, jurisdiction, access_token):
"""Retrieve schema for specific entity type, filing type, and jurisdiction"""
# Build query parameters
params = {
"entity_type": entity_type,
"filing_type": filing_type,
"jurisdiction": jurisdiction
}
response = requests.get(
"https://api.demo.singlefile.io/external-api/v1/schemas",
params=params,
headers={"Authorization": f"Bearer {access_token}"}
)
if response.status_code == 200:
schema = response.json()["data"]
return schema
elif response.status_code == 404:
raise Exception(f"Schema not found for {entity_type} {filing_type} in {jurisdiction}")
else:
raise Exception(f"Failed to retrieve schemas: {response.status_code}")
def get_formation_schema(entity_type, jurisdiction, access_token):
"""Retrieve formation schema for specific entity type and jurisdiction"""
return get_schema(entity_type, "FORMATION", jurisdiction, access_token)
# Get the formation schema
ACCESS_TOKEN = "your_bearer_token_here"
formation_schema = get_formation_schema("llc", "delaware", ACCESS_TOKEN)
print("Retrieved formation schema successfully")
print(formation_schema)const BASE_URL = "https://api.demo.singlefile.io";
async function getFormationSchema(entityType, jurisdiction, accessToken) {
const params = new URLSearchParams({
entity_type: entityType,
filing_type: "formation",
jurisdiction
});
const res = await fetch(`${BASE_URL}/external-api/v1/schemas?${params}`, {
headers: { Authorization: `Bearer ${accessToken}` }
});
if (res.status === 200) {
const { data } = await res.json();
return data;
}
if (res.status === 404) {
throw new Error(`Schema not found for ${entityType} formation in ${jurisdiction}`);
}
throw new Error(`Failed to retrieve schemas: ${res.status}`);
}
const ACCESS_TOKEN = "your_bearer_token_here";
const formationSchema = await getFormationSchema("llc", "delaware", ACCESS_TOKEN);
console.log("Retrieved formation schema successfully");
console.log(formationSchema);package main
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
)
const baseURL = "https://api.demo.singlefile.io"
func getFormationSchema(entityType, jurisdiction, accessToken string) (interface{}, error) {
params := url.Values{}
params.Set("entity_type", entityType)
params.Set("filing_type", "formation")
params.Set("jurisdiction", jurisdiction)
req, _ := http.NewRequest("GET", baseURL+"/external-api/v1/schemas?"+params.Encode(), nil)
req.Header.Set("Authorization", "Bearer "+accessToken)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode == 200 {
var result struct {
Data interface{} `json:"data"`
}
json.NewDecoder(resp.Body).Decode(&result)
return result.Data, nil
}
if resp.StatusCode == 404 {
return nil, fmt.Errorf("schema not found for %s formation in %s", entityType, jurisdiction)
}
return nil, fmt.Errorf("failed to retrieve schemas: %d", resp.StatusCode)
}
func main() {
accessToken := "your_bearer_token_here"
schema, err := getFormationSchema("llc", "delaware", accessToken)
if err != nil {
panic(err)
}
fmt.Println("Retrieved formation schema successfully")
fmt.Printf("%v\n", schema)
}using System.Net.Http;
using System.Text.Json;
var baseUrl = "https://api.demo.singlefile.io";
async Task<JsonElement> GetFormationSchemaAsync(string entityType, string jurisdiction, string accessToken)
{
var query = $"entity_type={Uri.EscapeDataString(entityType)}&filing_type=formation&jurisdiction={Uri.EscapeDataString(jurisdiction)}";
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {accessToken}");
var res = await client.GetAsync($"{baseUrl}/external-api/v1/schemas?{query}");
var json = await res.Content.ReadAsStringAsync();
var doc = JsonDocument.Parse(json);
if (res.StatusCode == System.Net.HttpStatusCode.OK)
return doc.RootElement.GetProperty("data").Clone();
if (res.StatusCode == System.Net.HttpStatusCode.NotFound)
throw new Exception($"Schema not found for {entityType} formation in {jurisdiction}");
throw new Exception($"Failed to retrieve schemas: {res.StatusCode}");
}
var accessToken = "your_bearer_token_here";
var formationSchema = await GetFormationSchemaAsync("llc", "delaware", accessToken);
Console.WriteLine("Retrieved formation schema successfully");
Console.WriteLine(formationSchema);Not all entity type and jurisdiction combinations are supported. The API returns a 404 if the requested combination is unavailable. Use the schema endpoint to validate before building payloads.
Example Schema Response (Delaware LLC):
| Field | Type | Required | Description |
|---|---|---|---|
entity_type | const llc | Yes | Entity type identifier |
filing_type | const formation | Yes | Filing action |
jurisdiction | const delaware | Yes | Target jurisdiction |
entity_name | string | Yes | Must include "LLC", "L.L.C.", or "Limited Liability Company" |
primary_contact | object | Yes | First name, last name, email, phone |
registered_agent | object | Conditional | Name and Delaware address (optional if document provided) |
authorized_person_name | string | Conditional | Signer name (optional if document provided) |
billing_contact | object | No | Billing contact details |
document | object | No | Base64-encoded file (PDF, JPEG, PNG, GIF, DOC, DOCX) |
GET /external-api/v1/schemas?entity_type=llc&filing_type=formation&jurisdiction=delaware
Step 3: Create & Validate Formation Payload
Build a payload that adheres to the schema requirements:
# Payload is built as JSON - use a heredoc or JSON file for curl -d
# Example: create payload.json with the structure below, then:
# curl -X POST "https://api.demo.singlefile.io/external-api/v1/orders?preview=True" \
# -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" -d @payload.jsondef create_formation_payload(organization_id, entity_name, entity_type, jurisdiction, schema):
"""Create formation payload based on schema requirements"""
payload = {
"organization_id": organization_id,
"entity_name": entity_name,
"entity_type": entity_type,
"jurisdiction": jurisdiction,
"filing_type": "formation"
}
# Add Delaware LLC specific fields
if jurisdiction.lower() == "delaware" and entity_type.lower() in ["llc", "limited liability company"]:
payload.update({
"primary_address": {
"street_address": "123 Innovation Drive",
"city": "San Francisco",
"state": "CA",
"postal_code": "94105",
"country": "US"
},
"mailing_address": {
"street_address": "123 Innovation Drive",
"city": "San Francisco",
"state": "CA",
"postal_code": "94105",
"country": "US"
},
"primary_contact": {
"first_name": "John",
"last_name": "Doe",
"email": "[email protected]",
"telephone_number": "+1-555-123-4567"
},
"registered_agent": {
"name": "Delaware Registered Agent Services",
"address": {
"street_address": "1000 N. West Street",
"city": "Wilmington",
"state": "DE",
"postal_code": "19801"
}
},
"authorized_person_name": "John Doe",
"comments": "Standard Delaware LLC formation",
"add_certified_copy": True,
})
return payload
def validate_payload_against_schema(payload, schema):
"""Validate payload against the retrieved schema"""
try:
validate(instance=payload, schema=schema)
print("✓ Payload validation successful")
return True
except ValidationError as e:
print(f"✗ Payload validation failed: {e.message}")
print(f" Path: {' -> '.join(str(p) for p in e.path)}")
return False
# Create and validate payload
formation_payload = create_formation_payload(
organization_id,
"Acme AI Solutions LLC",
"llc",
"delaware",
formation_schema
)
if not validate_payload_against_schema(formation_payload, formation_schema):
raise Exception("Formation payload validation failed")function createFormationPayload(organizationId, entityName, entityType, jurisdiction, schema) {
const payload = {
organization_id: organizationId,
entity_name: entityName,
entity_type: entityType,
jurisdiction: jurisdiction,
filing_type: "formation"
};
if (jurisdiction.toLowerCase() === "delaware" && ["llc", "limited liability company"].includes(entityType.toLowerCase())) {
Object.assign(payload, {
primary_address: { street_address: "123 Innovation Drive", city: "San Francisco", state: "CA", postal_code: "94105", country: "US" },
mailing_address: { street_address: "123 Innovation Drive", city: "San Francisco", state: "CA", postal_code: "94105", country: "US" },
primary_contact: { first_name: "John", last_name: "Doe", email: "[email protected]", telephone_number: "+1-555-123-4567" },
registered_agent: { name: "Delaware Registered Agent Services", address: { street_address: "1000 N. West Street", city: "Wilmington", state: "DE", postal_code: "19801" } },
authorized_person_name: "John Doe",
comments: "Standard Delaware LLC formation",
add_certified_copy: true
});
}
return payload;
}func createFormationPayload(organizationID, entityName, entityType, jurisdiction string, schema interface{}) map[string]interface{} {
payload := map[string]interface{}{
"organization_id": organizationID,
"entity_name": entityName,
"entity_type": entityType,
"jurisdiction": jurisdiction,
"filing_type": "formation",
}
if strings.ToLower(jurisdiction) == "delaware" && (strings.ToLower(entityType) == "llc" || strings.ToLower(entityType) == "limited liability company") {
payload["primary_address"] = map[string]interface{}{"street_address": "123 Innovation Drive", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US"}
payload["mailing_address"] = map[string]interface{}{"street_address": "123 Innovation Drive", "city": "San Francisco", "state": "CA", "postal_code": "94105", "country": "US"}
payload["primary_contact"] = map[string]interface{}{"first_name": "John", "last_name": "Doe", "email": "[email protected]", "telephone_number": "+1-555-123-4567"}
payload["registered_agent"] = map[string]interface{}{"name": "Delaware Registered Agent Services", "address": map[string]interface{}{"street_address": "1000 N. West Street", "city": "Wilmington", "state": "DE", "postal_code": "19801"}}
payload["authorized_person_name"] = "John Doe"
payload["comments"] = "Standard Delaware LLC formation"
payload["add_certified_copy"] = true
}
return payload
}var formationPayload = new Dictionary<string, object>
{
["organization_id"] = organizationId,
["entity_name"] = "Acme AI Solutions LLC",
["entity_type"] = "llc",
["jurisdiction"] = "delaware",
["filing_type"] = "formation",
["primary_contact"] = new { first_name = "John", last_name = "Doe", email = "[email protected]", telephone_number = "+1-555-123-4567" },
["registered_agent"] = new { name = "Delaware Registered Agent Services", address = new { street_address = "1000 N. West Street", city = "Wilmington", state = "DE", postal_code = "19801" } },
["authorized_person_name"] = "John Doe",
["comments"] = "Standard Delaware LLC formation",
["add_certified_copy"] = true
};Step 4: Preview the Formation Order
Use the preview functionality to validate the order before submission:
ACCESS_TOKEN="your_bearer_token_here"
# Use payload.json with your formation payload
curl -s -X POST "https://api.demo.singlefile.io/external-api/v1/orders?preview=True" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d @payload.jsonimport requests
def preview_formation_order(payload, access_token):
"""Preview formation order to catch any issues before submission"""
preview_payload = payload.copy()
params = {
"preview": True
}
response = requests.post(
"https://api.demo.singlefile.io/external-api/v1/orders",
json=preview_payload,
params=params,
headers={
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
)
if response.status_code == 200:
preview_result = response.json()["data"]
print("✓ Order preview successful")
# Check for warnings or errors
if "warnings" in preview_result:
print("⚠️ Preview warnings:")
for warning in preview_result["warnings"]:
print(f" - {warning}")
if "errors" in preview_result:
print("✗ Preview errors:")
for error in preview_result["errors"]:
print(f" - {error}")
return False
# Show preview details
if "preview_data" in preview_result:
preview_data = preview_result["preview_data"]
print(f" Filing fees: ${preview_data.get('filing_fees', 'N/A')}")
print(f" Processing time: {preview_data.get('processing_time', 'N/A')}")
print(f" Required documents: {len(preview_data.get('required_documents', []))}")
return True
elif response.status_code == 400:
error_data = response.json()
print(f"✗ Order preview failed: {error_data.get('error', {})}")
return False
else:
error_data = response.json()
print(f"✗ Order preview failed: {error_data.get('error', {}).get('message', 'Unknown error')}")
return False
# Preview the formation order
print("Previewing formation order...")
ACCESS_TOKEN = "your_bearer_token_here"
if not preview_formation_order(formation_payload, ACCESS_TOKEN):
raise Exception("Formation order preview failed - cannot proceed with submission")const BASE_URL = "https://api.demo.singlefile.io";
async function previewFormationOrder(payload, accessToken) {
const res = await fetch(`${BASE_URL}/external-api/v1/orders?preview=True`, {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
});
const data = await res.json();
if (res.status === 200) {
const result = data.data;
console.log("✓ Order preview successful");
if (result.warnings) result.warnings.forEach(w => console.log(" -", w));
if (result.errors) { result.errors.forEach(e => console.log(" -", e)); return false; }
if (result.preview_data) console.log(" Filing fees:", result.preview_data.filing_fees);
return true;
}
console.error("✗ Order preview failed:", data.error?.message);
return false;
}func previewFormationOrder(payload map[string]interface{}, accessToken string) (bool, error) {
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", baseURL+"/external-api/v1/orders?preview=True", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+accessToken)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return false, err
}
defer resp.Body.Close()
var result struct {
Data map[string]interface{} `json:"data"`
}
json.NewDecoder(resp.Body).Decode(&result)
if resp.StatusCode == 200 {
fmt.Println("✓ Order preview successful")
return true, nil
}
return false, fmt.Errorf("preview failed: %d", resp.StatusCode)
}async Task<bool> PreviewFormationOrderAsync(object payload, string accessToken)
{
var content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
var req = new HttpRequestMessage(HttpMethod.Post, $"{baseUrl}/external-api/v1/orders?preview=True") { Content = content };
req.Headers.Add("Authorization", $"Bearer {accessToken}");
var res = await client.SendAsync(req);
var json = await res.Content.ReadAsStringAsync();
if (res.StatusCode == System.Net.HttpStatusCode.OK)
{
Console.WriteLine("✓ Order preview successful");
return true;
}
Console.WriteLine("✗ Order preview failed");
return false;
}Step 5: Submit the Formation Order
If preview is successful, submit the actual order:
ACCESS_TOKEN="your_bearer_token_here"
curl -s -X POST "https://api.demo.singlefile.io/external-api/v1/orders" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d @payload.jsonimport requests
def submit_formation_order(payload, access_token):
"""Submit the actual formation order"""
response = requests.post(
"https://api.demo.singlefile.io/external-api/v1/orders",
json=payload,
headers={
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
)
if response.status_code == 201:
order = response.json()["data"]
print(f"✓ Formation order submitted successfully!")
print(f" Order ID: {order['order_id']}")
print(f" Status: {order['status']}")
print(f" Created: {order['created_at']}")
return order
else:
error_data = response.json()
print(f"✗ Formation order submission failed: {error_data.get('error', {}).get('message', 'Unknown error')}")
return None
# Submit the formation order
print("Submitting formation order...")
ACCESS_TOKEN = "your_bearer_token_here"
submitted_order = submit_formation_order(formation_payload, ACCESS_TOKEN)
if not submitted_order:
raise Exception("Failed to submit formation order")async function submitFormationOrder(payload, accessToken) {
const res = await fetch("https://api.demo.singlefile.io/external-api/v1/orders", {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
});
const data = await res.json();
if (res.status === 201) {
const order = data.data;
console.log("✓ Formation order submitted successfully!");
console.log(" Order ID:", order.order_id);
return order;
}
console.error("✗ Formation order submission failed");
return null;
}func submitFormationOrder(payload map[string]interface{}, accessToken string) (map[string]interface{}, error) {
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", baseURL+"/external-api/v1/orders", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+accessToken)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result struct {
Data map[string]interface{} `json:"data"`
}
json.NewDecoder(resp.Body).Decode(&result)
if resp.StatusCode == 201 {
fmt.Println("✓ Formation order submitted successfully!")
return result.Data, nil
}
return nil, fmt.Errorf("submission failed: %d", resp.StatusCode)
}async Task<JsonElement?> SubmitFormationOrderAsync(object payload, string accessToken)
{
var content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
var req = new HttpRequestMessage(HttpMethod.Post, $"{baseUrl}/external-api/v1/orders") { Content = content };
req.Headers.Add("Authorization", $"Bearer {accessToken}");
var res = await client.SendAsync(req);
var json = await res.Content.ReadAsStringAsync();
var doc = JsonDocument.Parse(json);
if (res.StatusCode == System.Net.HttpStatusCode.Created)
{
Console.WriteLine("✓ Formation order submitted successfully!");
return doc.RootElement.GetProperty("data").Clone();
}
return null;
}Complete Formation Workflow
Here's a complete function that orchestrates the entire formation process:
def complete_formation_workflow(org_name, org_domain, entity_name, entity_type, jurisdiction, access_token):
try:
organization_id = get_or_create_organization(org_name, org_domain, access_token)
formation_schema = get_formation_schema(entity_type, jurisdiction, access_token)
formation_payload = create_formation_payload(
organization_id, entity_name, entity_type, jurisdiction, formation_schema
)
if not preview_formation_order(formation_payload, access_token):
raise Exception("Order preview failed")
submitted_order = submit_formation_order(formation_payload, access_token)
if not submitted_order:
raise Exception("Order submission failed")
return {
"organization_id": organization_id,
"order_id": submitted_order["order_id"],
"status": "submitted"
}
except Exception as e:
print(f"Formation workflow failed: {e}")
raise
result = complete_formation_workflow(
org_name="Acme Ventures LLC",
org_domain="acmeventures.com",
entity_name="Acme AI Solutions LLC",
entity_type="llc",
jurisdiction="delaware",
access_token="your_bearer_token_here"
)async function completeFormationWorkflow(orgName, orgDomain, entityName, entityType, jurisdiction, accessToken) {
const organizationId = await getOrCreateOrganization(orgName, orgDomain, accessToken);
const formationSchema = await getFormationSchema(entityType, jurisdiction, accessToken);
const formationPayload = createFormationPayload(
organizationId, entityName, entityType, jurisdiction, formationSchema
);
if (!(await previewFormationOrder(formationPayload, accessToken))) {
throw new Error("Order preview failed");
}
const submittedOrder = await submitFormationOrder(formationPayload, accessToken);
if (!submittedOrder) throw new Error("Order submission failed");
return {
organization_id: organizationId,
order_id: submittedOrder.order_id,
status: "submitted"
};
}
const result = await completeFormationWorkflow(
"Acme Ventures LLC", "acmeventures.com",
"Acme AI Solutions LLC", "llc", "delaware",
"your_bearer_token_here"
);func completeFormationWorkflow(orgName, orgDomain, entityName, entityType, jurisdiction, accessToken string) (map[string]string, error) {
orgID, err := getOrCreateOrganization(orgName, orgDomain, accessToken)
if err != nil { return nil, err }
schema, err := getFormationSchema(entityType, jurisdiction, accessToken)
if err != nil { return nil, err }
payload := createFormationPayload(orgID, entityName, entityType, jurisdiction, schema)
if !previewFormationOrder(payload, accessToken) {
return nil, fmt.Errorf("order preview failed")
}
order := submitFormationOrder(payload, accessToken)
if order == nil { return nil, fmt.Errorf("order submission failed") }
return map[string]string{
"organization_id": orgID,
"order_id": fmt.Sprintf("%v", order["order_id"]),
"status": "submitted",
}, nil
}async Task<Dictionary<string, string>> CompleteFormationWorkflow(
string orgName, string orgDomain, string entityName,
string entityType, string jurisdiction, string token)
{
var orgId = await GetOrCreateOrganization(orgName, orgDomain, token);
var schema = await GetFormationSchema(entityType, jurisdiction, token);
var payload = CreateFormationPayload(orgId, entityName, entityType, jurisdiction, schema);
if (!(await PreviewFormationOrder(payload, token)))
throw new Exception("Order preview failed");
var order = await SubmitFormationOrder(payload, token);
if (order == null) throw new Exception("Order submission failed");
return new Dictionary<string, string> {
["organization_id"] = orgId,
["order_id"] = order.Value.GetProperty("order_id").GetString()!,
["status"] = "submitted"
};
}Document-Based Formation
When documents are provided,
registered_agentandauthorized_person_namefields become optional — SingleFile extracts this information automatically from the uploaded files.
Supported Document Types:
| Format | MIME Type |
|---|---|
application/pdf | |
| JPEG | image/jpeg |
| PNG | image/png |
| GIF | image/gif |
| Word (DOC) | application/msword |
| Word (DOCX) | application/vnd.openxmlformats-officedocument.wordprocessingml.document |
Method 1: Upload During Order Creation
Include the base64-encoded document in the order payload:
ACCESS_TOKEN="your_bearer_token_here"
# Base64 encode the document first: BASE64_DOC=$(base64 -i /path/to/formation_doc.pdf)
# Build JSON with document object and POST
curl -s -X POST "https://api.demo.singlefile.io/external-api/v1/orders" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_name":"Acme Technologies LLC","organization_id":"org_123","jurisdiction":"Delaware","filing_type":"FORMATION","entity_type":"Limited Liability Company","comments":"Standard LLC formation with registered agent document","document":{"filename":"formation_doc.pdf","content":"'$(base64 -i /path/to/formation_doc.pdf | tr -d '\n')'","content_type":"application/pdf"}}'import requests
import base64
def create_order_with_document(payload, document_path, access_token):
"""Create order with attached document"""
# Read and encode document
if document_path:
with open(document_path, 'rb') as file:
file_content = base64.b64encode(file.read()).decode('utf-8')
file_name = document_path.split('/')[-1]
payload["document"] = {
"filename": file_name,
"content": file_content,
"content_type": get_content_type(file_name)
}
response = requests.post(
"https://api.demo.singlefile.io/external-api/v1/orders",
json=payload,
headers={
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
)
if response.status_code == 201:
order = response.json()["data"]
print(f"✓ Order created with {len(documents)} documents")
return order
else:
error_data = response.json()
print(f"✗ Order creation failed: {error_data.get('error', {}).get('message', 'Unknown error')}")
return None
def get_content_type(filename):
"""Get MIME type based on file extension"""
extension = filename.lower().split('.')[-1]
content_types = {
'pdf': 'application/pdf',
'jpg': 'image/jpeg',
'jpeg': 'image/jpeg',
'png': 'image/png',
'gif': 'image/gif',
'doc': 'application/msword',
'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
}
return content_types.get(extension, 'application/octet-stream')
# Example usage
formation_payload = {
"entity_name": "Acme Technologies LLC",
"organization_id": "org_123",
"jurisdiction": "Delaware",
"filing_type": "FORMATION",
"entity_type": "Limited Liability Company",
"comments": "Standard LLC formation with registered agent document"
# Note: registered_agent and authorized_person_name are optional when documents are provided
}
document_path = "/path/to/formation_doc.pdf"
ACCESS_TOKEN = "your_bearer_token_here"
order = create_order_with_document(formation_payload, document_path, ACCESS_TOKEN)const fs = await import('fs');
const path = await import('path');
async function createOrderWithDocument(payload, documentPath, accessToken) {
if (documentPath) {
const buffer = fs.readFileSync(documentPath);
const base64Content = buffer.toString('base64');
const fileName = path.basename(documentPath);
const ext = path.extname(fileName).toLowerCase().slice(1);
const contentTypes = { pdf: 'application/pdf', jpg: 'image/jpeg', jpeg: 'image/jpeg', png: 'image/png', gif: 'image/gif', doc: 'application/msword', docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' };
payload.document = { filename: fileName, content: base64Content, content_type: contentTypes[ext] || 'application/octet-stream' };
}
const res = await fetch("https://api.demo.singlefile.io/external-api/v1/orders", {
method: "POST",
headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json" },
body: JSON.stringify(payload)
});
if (res.status === 201) {
const { data } = await res.json();
console.log("✓ Order created with document");
return data;
}
const err = await res.json();
console.error("✗ Order creation failed:", err.error?.message);
return null;
}import "encoding/base64"
import "os"
func createOrderWithDocument(payload map[string]interface{}, documentPath, accessToken string) (map[string]interface{}, error) {
if documentPath != "" {
data, _ := os.ReadFile(documentPath)
base64Content := base64.StdEncoding.EncodeToString(data)
fileName := filepath.Base(documentPath)
ext := strings.TrimPrefix(strings.ToLower(filepath.Ext(fileName)), ".")
contentTypes := map[string]string{"pdf": "application/pdf", "jpg": "image/jpeg", "png": "image/png", "gif": "image/gif"}
ct := contentTypes[ext]
if ct == "" {
ct = "application/octet-stream"
}
payload["document"] = map[string]interface{}{"filename": fileName, "content": base64Content, "content_type": ct}
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", baseURL+"/external-api/v1/orders", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+accessToken)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result struct {
Data map[string]interface{} `json:"data"`
}
json.NewDecoder(resp.Body).Decode(&result)
if resp.StatusCode == 201 {
return result.Data, nil
}
return nil, fmt.Errorf("order creation failed: %d", resp.StatusCode)
}var bytes = await File.ReadAllBytesAsync(documentPath);
var base64Content = Convert.ToBase64String(bytes);
var fileName = Path.GetFileName(documentPath);
var ext = Path.GetExtension(fileName).ToLowerInvariant().TrimStart('.');
var contentTypes = new Dictionary<string, string> { ["pdf"] = "application/pdf", ["jpg"] = "image/jpeg", ["png"] = "image/png" };
var contentType = contentTypes.GetValueOrDefault(ext, "application/octet-stream");
payload["document"] = new { filename = fileName, content = base64Content, content_type = contentType };
var content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");
var req = new HttpRequestMessage(HttpMethod.Post, $"{baseUrl}/external-api/v1/orders") { Content = content };
req.Headers.Add("Authorization", $"Bearer {accessToken}");
var res = await client.SendAsync(req);Method 2: Upload to Existing Order
Attach a document to an order that has already been created:
ORDER_ID="ord_12345"
ACCESS_TOKEN="your_bearer_token_here"
DOCUMENT_PATH="/path/to/formation_document.pdf"
BASE64_CONTENT=$(base64 -i "$DOCUMENT_PATH" | tr -d '\n')
FILE_NAME=$(basename "$DOCUMENT_PATH")
curl -s -X POST "https://api.demo.singlefile.io/external-api/v1/orders/$ORDER_ID/documents" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"filename\":\"$FILE_NAME\",\"content\":\"$BASE64_CONTENT\",\"content_type\":\"application/pdf\"}"import requests
import base64
def upload_document_to_order(order_id, document_path, access_token):
"""Upload document to an existing order"""
with open(document_path, 'rb') as file:
file_content = base64.b64encode(file.read()).decode('utf-8')
file_name = document_path.split('/')[-1]
document_data = {
"filename": file_name,
"content": file_content,
"content_type": get_content_type(file_name)
}
response = requests.post(
f"https://api.demo.singlefile.io/external-api/v1/orders/{order_id}/documents",
json=document_data,
headers={
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
)
if response.status_code == 201:
print(f"✓ Document '{file_name}' uploaded successfully")
else:
error_data = response.json()
print(f"✗ Failed to upload '{file_name}': {error_data.get('error', {}).get('message', 'Unknown error')}")
# Example usage
ORDER_ID = "ord_12345"
document_path = "/path/to/formation_document.pdf"
ACCESS_TOKEN = "your_bearer_token_here"
upload_document_to_order(ORDER_ID, document_path, ACCESS_TOKEN)import fs from 'fs';
import path from 'path';
async function uploadDocumentToOrder(orderId, documentPath, accessToken) {
const buffer = fs.readFileSync(documentPath);
const base64Content = buffer.toString('base64');
const fileName = path.basename(documentPath);
const ext = path.extname(fileName).toLowerCase().slice(1);
const contentTypes = { pdf: 'application/pdf', jpg: 'image/jpeg', png: 'image/png' };
const documentData = { filename: fileName, content: base64Content, content_type: contentTypes[ext] || 'application/octet-stream' };
const res = await fetch(`https://api.demo.singlefile.io/external-api/v1/orders/${orderId}/documents`, {
method: "POST",
headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json" },
body: JSON.stringify(documentData)
});
if (res.status === 201) {
console.log(`✓ Document '${fileName}' uploaded successfully`);
} else {
const err = await res.json();
console.error(`✗ Failed to upload '${fileName}':`, err.error?.message);
}
}func uploadDocumentToOrder(orderID, documentPath, accessToken string) error {
data, _ := os.ReadFile(documentPath)
base64Content := base64.StdEncoding.EncodeToString(data)
fileName := filepath.Base(documentPath)
ext := strings.TrimPrefix(strings.ToLower(filepath.Ext(fileName)), ".")
contentTypes := map[string]string{"pdf": "application/pdf", "jpg": "image/jpeg", "png": "image/png"}
ct := contentTypes[ext]
if ct == "" {
ct = "application/octet-stream"
}
docData := map[string]interface{}{"filename": fileName, "content": base64Content, "content_type": ct}
body, _ := json.Marshal(docData)
req, _ := http.NewRequest("POST", baseURL+"/external-api/v1/orders/"+orderID+"/documents", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+accessToken)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode == 201 {
fmt.Printf("✓ Document '%s' uploaded successfully\n", fileName)
return nil
}
return fmt.Errorf("upload failed: %d", resp.StatusCode)
}async Task UploadDocumentToOrderAsync(string orderId, string documentPath, string accessToken)
{
var bytes = await File.ReadAllBytesAsync(documentPath);
var base64Content = Convert.ToBase64String(bytes);
var fileName = Path.GetFileName(documentPath);
var ext = Path.GetExtension(fileName).ToLowerInvariant().TrimStart('.');
var contentTypes = new Dictionary<string, string> { ["pdf"] = "application/pdf", ["jpg"] = "image/jpeg", ["png"] = "image/png" };
var documentData = new { filename = fileName, content = base64Content, content_type = contentTypes.GetValueOrDefault(ext, "application/octet-stream") };
var content = new StringContent(JsonSerializer.Serialize(documentData), Encoding.UTF8, "application/json");
var req = new HttpRequestMessage(HttpMethod.Post, $"{baseUrl}/external-api/v1/orders/{orderId}/documents") { Content = content };
req.Headers.Add("Authorization", $"Bearer {accessToken}");
var res = await client.SendAsync(req);
if (res.StatusCode == System.Net.HttpStatusCode.Created)
Console.WriteLine($"✓ Document '{fileName}' uploaded successfully");
else
Console.WriteLine($"✗ Failed to upload '{fileName}'");
}Document Validation & Error Handling
When a document is uploaded, it undergoes validation. Handle errors like this:
def handle_document_validation_errors(response):
if response.status_code == 400:
error_data = response.json()
errors = error_data.get("error", {}).get("details", [])
for error in errors:
if "document" in error:
doc_name = error["document"].get("filename", "Unknown")
for doc_error in error["document"].get("errors", []):
print(f" {doc_name}: {doc_error}")
else:
print(f" {error}")
return False
elif response.status_code == 201:
return True
return Falsefunction handleDocumentValidationErrors(response, data) {
if (response.status === 400) {
const errors = data?.error?.details ?? [];
for (const error of errors) {
if (error.document) {
const docName = error.document.filename ?? "Unknown";
for (const docError of error.document.errors ?? []) {
console.log(` ${docName}: ${docError}`);
}
} else {
console.log(` ${JSON.stringify(error)}`);
}
}
return false;
}
return response.status === 201;
}func handleDocumentValidationErrors(resp *http.Response) bool {
if resp.StatusCode == 400 {
var errResp struct {
Error struct {
Details []map[string]interface{} `json:"details"`
} `json:"error"`
}
json.NewDecoder(resp.Body).Decode(&errResp)
for _, detail := range errResp.Error.Details {
if doc, ok := detail["document"].(map[string]interface{}); ok {
fmt.Printf(" %s: %v\n", doc["filename"], doc["errors"])
} else {
fmt.Printf(" %v\n", detail)
}
}
return false
}
return resp.StatusCode == 201
}bool HandleDocumentValidationErrors(HttpResponseMessage response, string content)
{
if (response.StatusCode == System.Net.HttpStatusCode.BadRequest)
{
var doc = JsonDocument.Parse(content);
var details = doc.RootElement.GetProperty("error").GetProperty("details");
foreach (var detail in details.EnumerateArray())
{
if (detail.TryGetProperty("document", out var docErr))
{
var name = docErr.GetProperty("filename").GetString();
foreach (var e in docErr.GetProperty("errors").EnumerateArray())
Console.WriteLine($" {name}: {e.GetString()}");
}
}
return false;
}
return response.StatusCode == System.Net.HttpStatusCode.Created;
}Fields that become optional with document upload:
registered_agent— extracted from the uploaded formation documentauthorized_person_name— extracted from the uploaded formation document
Complete Document-Based Workflow
import base64
def complete_formation_with_document(org_name, org_domain, entity_name,
entity_type, jurisdiction, document_path, access_token):
organization_id = get_or_create_organization(org_name, org_domain, access_token)
formation_schema = get_formation_schema(entity_type, jurisdiction, access_token)
payload = {
"organization_id": organization_id,
"entity_name": entity_name,
"entity_type": entity_type,
"jurisdiction": jurisdiction,
"filing_type": "formation"
}
if document_path:
with open(document_path, "rb") as f:
payload["document"] = {
"filename": document_path.split("/")[-1],
"content": base64.b64encode(f.read()).decode("utf-8"),
"content_type": "application/pdf"
}
if not preview_formation_order(payload, access_token):
raise Exception("Preview failed")
order = submit_formation_order(payload, access_token)
if not order:
raise Exception("Submission failed")
return {"organization_id": organization_id, "order_id": order["order_id"]}
result = complete_formation_with_document(
"Acme Ventures LLC", "acmeventures.com",
"Acme AI Solutions LLC", "llc", "delaware",
"/path/to/formation_doc.pdf", "your_bearer_token_here"
)import { readFile } from "fs/promises";
import { basename } from "path";
async function completeFormationWithDocument(orgName, orgDomain, entityName,
entityType, jurisdiction, documentPath, accessToken) {
const organizationId = await getOrCreateOrganization(orgName, orgDomain, accessToken);
const payload = {
organization_id: organizationId,
entity_name: entityName,
entity_type: entityType,
jurisdiction: jurisdiction,
filing_type: "formation"
};
if (documentPath) {
const fileBuffer = await readFile(documentPath);
payload.document = {
filename: basename(documentPath),
content: fileBuffer.toString("base64"),
content_type: "application/pdf"
};
}
if (!(await previewFormationOrder(payload, accessToken)))
throw new Error("Preview failed");
const order = await submitFormationOrder(payload, accessToken);
if (!order) throw new Error("Submission failed");
return { organization_id: organizationId, order_id: order.order_id };
}func completeFormationWithDocument(orgName, orgDomain, entityName,
entityType, jurisdiction, documentPath, accessToken string) (map[string]string, error) {
orgID, err := getOrCreateOrganization(orgName, orgDomain, accessToken)
if err != nil { return nil, err }
payload := map[string]interface{}{
"organization_id": orgID,
"entity_name": entityName,
"entity_type": entityType,
"jurisdiction": jurisdiction,
"filing_type": "formation",
}
if documentPath != "" {
data, err := os.ReadFile(documentPath)
if err != nil { return nil, err }
payload["document"] = map[string]string{
"filename": filepath.Base(documentPath),
"content": base64.StdEncoding.EncodeToString(data),
"content_type": "application/pdf",
}
}
if !previewFormationOrder(payload, accessToken) {
return nil, fmt.Errorf("preview failed")
}
order := submitFormationOrder(payload, accessToken)
if order == nil { return nil, fmt.Errorf("submission failed") }
return map[string]string{
"organization_id": orgID,
"order_id": fmt.Sprintf("%v", order["order_id"]),
}, nil
}async Task<Dictionary<string, string>> CompleteFormationWithDocument(
string orgName, string orgDomain, string entityName,
string entityType, string jurisdiction, string? documentPath, string token)
{
var orgId = await GetOrCreateOrganization(orgName, orgDomain, token);
var payload = new Dictionary<string, object> {
["organization_id"] = orgId,
["entity_name"] = entityName,
["entity_type"] = entityType,
["jurisdiction"] = jurisdiction,
["filing_type"] = "formation"
};
if (!string.IsNullOrEmpty(documentPath))
{
var bytes = await File.ReadAllBytesAsync(documentPath);
payload["document"] = new Dictionary<string, string> {
["filename"] = Path.GetFileName(documentPath),
["content"] = Convert.ToBase64String(bytes),
["content_type"] = "application/pdf"
};
}
if (!(await PreviewFormationOrder(payload, token)))
throw new Exception("Preview failed");
var order = await SubmitFormationOrder(payload, token);
if (order == null) throw new Exception("Submission failed");
return new Dictionary<string, string> {
["organization_id"] = orgId,
["order_id"] = order.Value.GetProperty("order_id").GetString()!
};
}What's Next?
Now that you've formed a business entity, here are common next steps:
- EIN Filing Workflow — Obtain a federal tax identification number for your new entity
- Document Management — Search, filter, and download formation documents
- Webhook Setup — Get real-time notifications when your formation order completes
- Annual Report Filing — Set up automated compliance filings to maintain good standing
Updated about 1 month ago
