Skip to main content

Prerequisites

Before you begin, ensure you have:
  • Python 3.12 or higher installed
  • A Factus account (sandbox or production)
  • Basic familiarity with REST APIs and Python
Don’t have a Factus account? You can use our sandbox credentials to get started immediately.

Installation

1

Clone the Repository

Clone the Factus API repository and navigate to the project directory:
git clone <repo-url>
cd factus-api
2

Create Virtual Environment

Create and activate a Python virtual environment:
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
Using a virtual environment isolates your project dependencies from your system Python installation.
3

Install Dependencies

Install the required Python packages:
pip install -r requirements.txt
This installs FastAPI, httpx, pydantic, and other dependencies.
4

Configure Environment Variables

Create a .env file in the project root with your configuration:
cp .env.example .env
Edit the .env file with your credentials:
# Factus API Configuration
FACTUS_BASE_URL=https://api-sandbox.factus.com.co
FACTUS_CLIENT_ID=your_client_id
FACTUS_CLIENT_SECRET=your_client_secret

# Local API Security
SECRET_KEY=your_random_secret_key_here
Generate a strong SECRET_KEY for JWT token signing. You can generate one using:
openssl rand -hex 32
5

Start the Server

Launch the FastAPI development server:
uvicorn app.src.main:app --reload --host 0.0.0.0 --port 8000
The server will start at http://localhost:8000
The --reload flag enables auto-reload on code changes during development.
6

Verify Installation

Open your browser and navigate to:Interactive API Docs: http://localhost:8000/api/v1/docsYou should see the Swagger UI with all available endpoints.

Making Your First API Calls

The Factus API uses a dual authentication system. You need:
  1. A local JWT token (from /api/v1/auth/login)
  2. A Factus access token (from /api/v1/auth/factus/login)
Let’s walk through the complete workflow:

Step 1: Local Authentication

First, obtain a local JWT token using the mock credentials:
curl -X POST "http://localhost:8000/api/v1/auth/login" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "username=admin&password=admin123"
Response:
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer"
}
Save the access_token value - you’ll need it for all subsequent requests.

Step 2: Factus Authentication

Next, authenticate with Factus to get a Factus access token:
curl -X POST "http://localhost:8000/api/v1/auth/factus/login" \
  -H "Authorization: Bearer YOUR_LOCAL_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "sandbox2024%"
  }'
Response:
{
  "success": true,
  "message": "Autenticación exitosa",
  "data": {
    "access_token": "factus_access_token_here",
    "refresh_token": "factus_refresh_token_here",
    "expires_in": 3600,
    "token_type": "Bearer"
  },
  "errors": null
}
Save both the access_token and refresh_token from the response. The access token expires after 1 hour.

Step 3: Create Your First Invoice

Now you can create an invoice using both tokens:
curl -X POST "http://localhost:8000/api/v1/invoices/" \
  -H "Authorization: Bearer YOUR_LOCAL_JWT" \
  -H "X-Factus-Token: YOUR_FACTUS_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "numbering_range_id": 8,
    "document": "01",
    "reference_code": "REF-2024-001",
    "observation": "Factura de prueba",
    "payment_method_code": "10",
    "payment_form": "1",
    "customer": {
      "identification_document_id": 3,
      "identification": "1234567890",
      "names": "Juan Pérez",
      "email": "[email protected]",
      "phone": "3001234567",
      "address": "Calle 123 #45-67",
      "municipality_id": 1,
      "legal_organization_id": 1,
      "tribute_id": 1
    },
    "items": [
      {
        "code_reference": "PROD-001",
        "name": "Producto de Ejemplo",
        "quantity": 2,
        "price": 100000.00,
        "discount_rate": 0.00,
        "tax_rate": 19.00,
        "unit_measure_id": 1,
        "standard_code_id": 1,
        "is_excluded": 0,
        "tribute_id": 1
      }
    ]
  }'
Response:
{
  "success": true,
  "message": "Factura creada exitosamente",
  "data": {
    "number": "SETP1",
    "prefix": "SETP",
    "cufe": "abc123def456...",
    "qr_url": "https://catalogo-vpfe.dian.gov.co/Document/FindDocument?documentKey=abc123...",
    "status": "success",
    "message": "Factura validada por DIAN"
  },
  "errors": null
}
The reference_code must be unique for each invoice. Use a timestamp or UUID to ensure uniqueness.

Step 4: Download Invoice Documents

Retrieve the invoice PDF or XML using the invoice number from the previous response:
curl -X GET "http://localhost:8000/api/v1/invoices/SETP1/pdf" \
  -H "Authorization: Bearer YOUR_LOCAL_JWT" \
  -H "X-Factus-Token: YOUR_FACTUS_ACCESS_TOKEN"
Response:
{
  "success": true,
  "message": "PDF obtenido exitosamente",
  "data": {
    "file_name": "SETP1.pdf",
    "file_content": "JVBERi0xLjQKJeLjz9MKMy...",
    "extension": "pdf"
  },
  "errors": null
}
The file_content is base64-encoded. Decode it to save the actual file.

Sandbox Credentials

Use these credentials to test the API without a production Factus account:
FieldValue
Base URLhttps://api-sandbox.factus.com.co
Email[email protected]
Passwordsandbox2024%
Numbering Range ID8 (prefix SETP)
Local Mock User:
  • Username: admin
  • Password: admin123
Sandbox credentials are for testing only. Never use them in production environments.

Common Operations

Refresh Factus Token

Factus access tokens expire after 1 hour. Use the refresh token to get a new access token:
curl -X POST "http://localhost:8000/api/v1/auth/factus/refresh" \
  -H "Authorization: Bearer YOUR_LOCAL_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "refresh_token": "YOUR_FACTUS_REFRESH_TOKEN"
  }'

Get Invoice Details

Retrieve full invoice information:
curl -X GET "http://localhost:8000/api/v1/invoices/SETP1" \
  -H "Authorization: Bearer YOUR_LOCAL_JWT" \
  -H "X-Factus-Token: YOUR_FACTUS_ACCESS_TOKEN"

Send Invoice by Email

Email the invoice to a customer:
curl -X POST "http://localhost:8000/api/v1/invoices/SETP1/send-email" \
  -H "Authorization: Bearer YOUR_LOCAL_JWT" \
  -H "X-Factus-Token: YOUR_FACTUS_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]"
  }'

Query Invoice Events (RADIAN)

Get the event history for an invoice:
curl -X GET "http://localhost:8000/api/v1/invoices/SETP1/events" \
  -H "Authorization: Bearer YOUR_LOCAL_JWT" \
  -H "X-Factus-Token: YOUR_FACTUS_ACCESS_TOKEN"

Next Steps

API Reference

Explore all endpoints and request schemas

Authentication Guide

Deep dive into the authentication system

Invoice Guide

Learn about invoice creation and management

Reference Data

Understand municipalities, taxes, and units

Troubleshooting

Server won’t start

  • Verify Python 3.12+ is installed: python --version
  • Ensure all dependencies are installed: pip install -r requirements.txt
  • Check that port 8000 is not in use by another application

Authentication fails

  • Verify your .env file has the correct Factus credentials
  • Ensure you’re using the correct sandbox credentials
  • Check that both tokens are included in protected endpoint requests

Invoice creation fails

  • Verify numbering_range_id is valid (use /api/v1/lookups/numbering-ranges)
  • Ensure reference_code is unique
  • Validate all required fields are present in the request body
  • Check that decimal values have maximum 2 decimal places
Enable detailed logging by checking the console output when running with --reload. All errors are logged with detailed messages.

Build docs developers (and LLMs) love