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 PayloadDocument-Based
Best forAutomated systems, full control over every fieldExisting docs, bulk processing, reduced data entry
Required fieldsAll fields mandatoryregistered_agent and authorized_person_name auto-extracted
Setup time15-30 min10-20 min
Per formation2-5 min1-3 min
Processing1-3 business days1-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 the entity_type parameter.

ParameterDescriptionExamples
entity_typeType of business entityllc, corporation, limited partnership
filing_typeFiling actionformation, foreign qualification
jurisdictionState for filingdelaware, 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):

FieldTypeRequiredDescription
entity_typeconst llcYesEntity type identifier
filing_typeconst formationYesFiling action
jurisdictionconst delawareYesTarget jurisdiction
entity_namestringYesMust include "LLC", "L.L.C.", or "Limited Liability Company"
primary_contactobjectYesFirst name, last name, email, phone
registered_agentobjectConditionalName and Delaware address (optional if document provided)
authorized_person_namestringConditionalSigner name (optional if document provided)
billing_contactobjectNoBilling contact details
documentobjectNoBase64-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.json
def 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.json
import 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.json
import 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_agent and authorized_person_name fields become optional — SingleFile extracts this information automatically from the uploaded files.

Supported Document Types:

FormatMIME Type
PDFapplication/pdf
JPEGimage/jpeg
PNGimage/png
GIFimage/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 False
function 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 document
  • authorized_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: