MENU navbar-image

Introduction

API RESTful para gestión de contribuyentes, categorías, documentos emitidos, documentos recibidos y reportes tributarios.

Esta documentación proporciona toda la información necesaria para trabajar con la API de Taxo Impuestos.

## Ambientes

La API está disponible en los siguientes ambientes:

| Ambiente | URL | Descripción |
|----------|-----|-------------|
| **Staging** | `https://ec-demo.taxo.co` | Ambiente de pruebas y desarrollo |
| **Producción** | `https://ec-impuestos.taxo.co` | Ambiente productivo *(próximamente)* |

<aside class="warning">⚠️ Actualmente esta documentación apunta al ambiente de <strong>Staging</strong>. Los ejemplos de código usan la URL de staging.</aside>

## Autenticación

Todas las peticiones a la API requieren dos headers:
- **x-api-key**: Tu API key proporcionado por TWS
- **x-organization-id**: Tu organization ID de TWS

## Rate Limiting

La API está limitada a 60 peticiones por minuto por API key.

<aside>A medida que navegues por la documentación, verás ejemplos de código en diferentes lenguajes en el área oscura a la derecha.</aside>

Authenticating requests

To authenticate requests, include a x-api-key header with the value "YOUR_API_KEY_HERE".

All authenticated endpoints are marked with a requires authentication badge in the documentation below.

Puedes obtener tu API key y Organization ID desde tu dashboard de TWS.

Debes incluir también el header x-organization-id con tu Organization ID.

Taxpayers

API endpoints for managing taxpayers and their related data.

List taxpayers

requires authentication

Retrieves a paginated list of all taxpayers belonging to the authenticated organization. You can filter and sort the results using query parameters.

Example request:
curl --request GET \
    --get "https://ec-demo.taxo.co/api/v1/taxpayers?page=1&per_page=20&sort=-created_at&search=Empresa+S.A.&status=1&iva_period=MENSUAL&tax_regime_cat=GENERAL&declaration_day=10" \
    --header "x-api-key: YOUR_API_KEY_HERE" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --header "x-organization-id: {YOUR_ORGANIZATION_ID}"
const url = new URL(
    "https://ec-demo.taxo.co/api/v1/taxpayers"
);

const params = {
    "page": "1",
    "per_page": "20",
    "sort": "-created_at",
    "search": "Empresa S.A.",
    "status": "1",
    "iva_period": "MENSUAL",
    "tax_regime_cat": "GENERAL",
    "declaration_day": "10",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "x-api-key": "YOUR_API_KEY_HERE",
    "Content-Type": "application/json",
    "Accept": "application/json",
    "x-organization-id": "{YOUR_ORGANIZATION_ID}",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://ec-demo.taxo.co/api/v1/taxpayers';
$response = $client->get(
    $url,
    [
        'headers' => [
            'x-api-key' => 'YOUR_API_KEY_HERE',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
            'x-organization-id' => '{YOUR_ORGANIZATION_ID}',
        ],
        'query' => [
            'page' => '1',
            'per_page' => '20',
            'sort' => '-created_at',
            'search' => 'Empresa S.A.',
            'status' => '1',
            'iva_period' => 'MENSUAL',
            'tax_regime_cat' => 'GENERAL',
            'declaration_day' => '10',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://ec-demo.taxo.co/api/v1/taxpayers'
params = {
  'page': '1',
  'per_page': '20',
  'sort': '-created_at',
  'search': 'Empresa S.A.',
  'status': '1',
  'iva_period': 'MENSUAL',
  'tax_regime_cat': 'GENERAL',
  'declaration_day': '10',
}
headers = {
  'x-api-key': 'YOUR_API_KEY_HERE',
  'Content-Type': 'application/json',
  'Accept': 'application/json',
  'x-organization-id': '{YOUR_ORGANIZATION_ID}'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (200, Success):


{
    "status": "success",
    "message": "Taxpayers retrieved successfully",
    "data": {
        "taxpayers": [
            {
                "id": 144,
                "ulid": "01HZXXX...",
                "tax_number": "1726051285001",
                "business_name": "EMPRESA DEMO S.A.",
                "trade_name": "DEMO",
                "tax_payer_status": "ACTIVE",
                "tax_regime": "general",
                "tax_regime_cat": "general",
                "iva_period": "monthly",
                "declaration_day": 12,
                "required_to_keep_accounts": "SI",
                "withholding_agent": "SI",
                "special_contributor": "NO",
                "economic_activity": "Actividades de consultoría de gestión empresarial",
                "start_activities_date": "2020-01-15T00:00:00.000000Z",
                "created_at": "2024-01-15T10:30:00.000000Z",
                "updated_at": "2024-01-15T10:30:00.000000Z"
            }
        ]
    },
    "meta": {
        "pagination": {
            "total": 5,
            "count": 5,
            "per_page": 20,
            "current_page": 1,
            "total_pages": 1
        },
        "filters": {
            "status": "ACTIVE"
        }
    }
}
 

Example response (401, Unauthorized):


{
    "status": "error",
    "message": "Invalid API key or organization ID",
    "code": "UNAUTHORIZED"
}
 

Example response (500, Server error):


{
    "status": "error",
    "message": "An error occurred while retrieving taxpayers",
    "code": "SERVER_ERROR"
}
 

Request      

GET api/v1/taxpayers

Headers

x-api-key        

Example: YOUR_API_KEY_HERE

Content-Type        

Example: application/json

Accept        

Example: application/json

x-organization-id        

Example: {YOUR_ORGANIZATION_ID}

Query Parameters

page   integer  optional    

Page number for pagination. El campo value debe ser al menos 1. Example: 1

per_page   integer  optional    

Number of items per page (max 100). El campo value debe ser al menos 1. El campo value no debe ser mayor que 100. Example: 20

sort   string  optional    

Sort field and direction. Prefix with "-" for descending order. Example: -created_at

Must be one of:
  • business_name
  • -business_name
  • tax_number
  • -tax_number
  • next_declaration
  • -next_declaration
  • created_at
  • -created_at
search   string  optional    

Search term to filter by business name or tax number. El campo value no debe ser mayor que 255 caracteres. Example: Empresa S.A.

status   integer  optional    

Filter by status (0=inactive, 1=active). Example: 1

Must be one of:
  • 0
  • 1
iva_period   string  optional    

Filter by IVA period (MENSUAL, SEMESTRAL). Example: MENSUAL

Must be one of:
  • MENSUAL
  • SEMESTRAL
tax_regime_cat   string  optional    

Filter by tax regime category. Example: GENERAL

Must be one of:
  • RISE
  • GENERAL
  • ESPECIAL
declaration_day   integer  optional    

Filter by declaration day (1-28). El campo value debe ser al menos 1. El campo value no debe ser mayor que 28. Example: 10

Create a new taxpayer

requires authentication

Creates a new taxpayer in your organization after validating that the tax identifier exists in the TWS (Tax Web Services) registry. Accepts RUC (13 digits), Cédula (10 digits), or Passport.

This endpoint will:

  1. Validate the taxpayer doesn't already exist in your organization
  2. Query the TWS registry API to verify the identifier is valid and active
  3. Create the taxpayer with all available data from TWS
  4. Automatically create default categories for document classification
  5. Set up auto-categorization rules

Note: This process may take 5-10 seconds as it queries external services.

Example request:
curl --request POST \
    "https://ec-demo.taxo.co/api/v1/taxpayers" \
    --header "x-api-key: YOUR_API_KEY_HERE" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --header "x-organization-id: {YOUR_ORGANIZATION_ID}" \
    --data "{
    \"taxpayerId\": \"1726051285001\"
}"
const url = new URL(
    "https://ec-demo.taxo.co/api/v1/taxpayers"
);

const headers = {
    "x-api-key": "YOUR_API_KEY_HERE",
    "Content-Type": "application/json",
    "Accept": "application/json",
    "x-organization-id": "{YOUR_ORGANIZATION_ID}",
};

let body = {
    "taxpayerId": "1726051285001"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://ec-demo.taxo.co/api/v1/taxpayers';
$response = $client->post(
    $url,
    [
        'headers' => [
            'x-api-key' => 'YOUR_API_KEY_HERE',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
            'x-organization-id' => '{YOUR_ORGANIZATION_ID}',
        ],
        'json' => [
            'taxpayerId' => '1726051285001',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://ec-demo.taxo.co/api/v1/taxpayers'
payload = {
    "taxpayerId": "1726051285001"
}
headers = {
  'x-api-key': 'YOUR_API_KEY_HERE',
  'Content-Type': 'application/json',
  'Accept': 'application/json',
  'x-organization-id': '{YOUR_ORGANIZATION_ID}'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (201, Taxpayer created successfully):


{
    "status": "success",
    "message": "Taxpayer created successfully",
    "data": {
        "taxpayer": {
            "id": "01JDXYZ123ABC456DEF789GHI",
            "tax_number": "1726051285001",
            "business_name": "AGUIRRE MEJIA AIDA ISABEL",
            "legal_name": "AGUIRRE MEJIA AIDA ISABEL",
            "email": null,
            "phone": null,
            "status": 1,
            "tax_payer_status": "ACTIVO",
            "economic_activity": "VENTA AL POR MAYOR DE FRUTAS",
            "tax_regime": "GENERAL",
            "tax_regime_cat": "general",
            "iva_period": "monthly",
            "category": null,
            "required_to_keep_accounts": "NO",
            "withholding_agent": "NO",
            "special_contributor": "NO",
            "declaration_day": 12,
            "next_declaration": null,
            "start_activities_date": "2018-09-04",
            "last_sync_at": null,
            "created_at": "2024-12-02 15:30:45",
            "updated_at": "2024-12-02 15:30:45"
        }
    }
}
 

Example response (401, Unauthorized):


{
    "status": "error",
    "message": "Invalid API key or organization ID",
    "code": "UNAUTHORIZED"
}
 

Example response (404, Taxpayer not found in TWS):


{
    "status": "error",
    "message": "Taxpayer not found in TWS. Please verify the taxpayer ID",
    "code": "TAXPAYER_NOT_FOUND_IN_TWS"
}
 

Example response (409, Taxpayer already exists):


{
    "status": "error",
    "message": "Taxpayer already exists for this organization",
    "code": "TAXPAYER_ALREADY_EXISTS"
}
 

Example response (422, Validation error):


{
    "status": "error",
    "message": "Validation failed",
    "code": "VALIDATION_ERROR",
    "errors": {
        "taxpayerId": [
            "The taxpayer ID can only contain letters, numbers, and hyphens"
        ]
    }
}
 

Example response (500, Internal server error):


{
    "status": "error",
    "message": "Failed to create taxpayer due to an internal error",
    "code": "INTERNAL_SERVER_ERROR"
}
 

Example response (503, TWS service unavailable):


{
    "status": "error",
    "message": "Unable to verify taxpayer with TWS app",
    "code": "TWS_SERVICE_UNAVAILABLE"
}
 

Example response (504, TWS service timeout):


{
    "status": "error",
    "message": "TWS service timeout. Please try again later",
    "code": "TWS_SERVICE_TIMEOUT"
}
 

Request      

POST api/v1/taxpayers

Headers

x-api-key        

Example: YOUR_API_KEY_HERE

Content-Type        

Example: application/json

Accept        

Example: application/json

x-organization-id        

Example: {YOUR_ORGANIZATION_ID}

Body Parameters

taxpayerId   string     

Ecuadorian tax identifier. Can be: RUC (13 digits), Cédula (10 digits), or Passport (alphanumeric). Must match the regex /^[a-zA-Z0-9-]+$/. El campo value debe ser de al menos 5 caracteres. El campo value no debe ser mayor que 20 caracteres. Example: 1726051285001

Get a specific taxpayer

requires authentication

Retrieves detailed information for a specific taxpayer identified by their RUC number. The taxpayer must belong to the authenticated organization.

Example request:
curl --request GET \
    --get "https://ec-demo.taxo.co/api/v1/taxpayers/1726051285001" \
    --header "x-api-key: YOUR_API_KEY_HERE" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --header "x-organization-id: {YOUR_ORGANIZATION_ID}"
const url = new URL(
    "https://ec-demo.taxo.co/api/v1/taxpayers/1726051285001"
);

const headers = {
    "x-api-key": "YOUR_API_KEY_HERE",
    "Content-Type": "application/json",
    "Accept": "application/json",
    "x-organization-id": "{YOUR_ORGANIZATION_ID}",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://ec-demo.taxo.co/api/v1/taxpayers/1726051285001';
$response = $client->get(
    $url,
    [
        'headers' => [
            'x-api-key' => 'YOUR_API_KEY_HERE',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
            'x-organization-id' => '{YOUR_ORGANIZATION_ID}',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://ec-demo.taxo.co/api/v1/taxpayers/1726051285001'
headers = {
  'x-api-key': 'YOUR_API_KEY_HERE',
  'Content-Type': 'application/json',
  'Accept': 'application/json',
  'x-organization-id': '{YOUR_ORGANIZATION_ID}'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200, Success):


{
    "status": "success",
    "message": "Taxpayer retrieved successfully",
    "data": {
        "taxpayer": {
            "id": 144,
            "ulid": "01HZXXX...",
            "tax_number": "1726051285001",
            "business_name": "EMPRESA DEMO S.A.",
            "trade_name": "DEMO",
            "address": "Av. Principal 123 y Secundaria",
            "phone": "0987654321",
            "email": "contacto@demo.com",
            "legal_representatives": "Juan Pérez, María González",
            "economic_activity": "Actividades de consultoría de gestión empresarial",
            "tax_payer_status": "ACTIVE",
            "tax_payer_type": "PERSONA JURÍDICA",
            "tax_regime": "general",
            "tax_regime_cat": "general",
            "category": null,
            "iva_period": "monthly",
            "declaration_day": 12,
            "required_to_keep_accounts": "SI",
            "withholding_agent": "SI",
            "special_contributor": "NO",
            "ghost_taxpayer": "NO",
            "nonexistent_transactions": "NO",
            "start_activities_date": "2020-01-15T00:00:00.000000Z",
            "cessation_date": null,
            "restart_activities_date": null,
            "information_update_date": "2024-01-15T00:00:00.000000Z",
            "created_at": "2024-01-15T10:30:00.000000Z",
            "updated_at": "2024-01-15T10:30:00.000000Z"
        }
    }
}
 

Example response (401, Unauthorized):


{
    "status": "error",
    "message": "Invalid API key or organization ID",
    "code": "UNAUTHORIZED"
}
 

Example response (404, Taxpayer not found):


{
    "status": "error",
    "message": "Taxpayer not found",
    "code": "TAXPAYER_NOT_FOUND"
}
 

Example response (500, Server error):


{
    "status": "error",
    "message": "An error occurred while retrieving the taxpayer",
    "code": "SERVER_ERROR"
}
 

Request      

GET api/v1/taxpayers/{taxNumber}

Headers

x-api-key        

Example: YOUR_API_KEY_HERE

Content-Type        

Example: application/json

Accept        

Example: application/json

x-organization-id        

Example: {YOUR_ORGANIZATION_ID}

URL Parameters

taxNumber   string     

The taxpayer's RUC number (13 digits). Example: 1726051285001

Get taxpayer categories

requires authentication

Retrieves a paginated list of categories for a specific taxpayer. Categories are used to classify purchase and sales documents.

Example request:
curl --request GET \
    --get "https://ec-demo.taxo.co/api/v1/taxpayers/1726051285001/categories?page=1&per_page=20&document_type=sales&category_type=commercial_expenses&enabled=1&editable=1&search=Alimentaci%C3%B3n&filter[document_type]=purchases&filter[category_type]=personal_expenses&filter[search]=vmqeopfuudtdsufvyvddq" \
    --header "x-api-key: YOUR_API_KEY_HERE" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --header "x-organization-id: {YOUR_ORGANIZATION_ID}"
const url = new URL(
    "https://ec-demo.taxo.co/api/v1/taxpayers/1726051285001/categories"
);

const params = {
    "page": "1",
    "per_page": "20",
    "document_type": "sales",
    "category_type": "commercial_expenses",
    "enabled": "1",
    "editable": "1",
    "search": "Alimentación",
    "filter[document_type]": "purchases",
    "filter[category_type]": "personal_expenses",
    "filter[search]": "vmqeopfuudtdsufvyvddq",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "x-api-key": "YOUR_API_KEY_HERE",
    "Content-Type": "application/json",
    "Accept": "application/json",
    "x-organization-id": "{YOUR_ORGANIZATION_ID}",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
$client = new \GuzzleHttp\Client();
$url = 'https://ec-demo.taxo.co/api/v1/taxpayers/1726051285001/categories';
$response = $client->get(
    $url,
    [
        'headers' => [
            'x-api-key' => 'YOUR_API_KEY_HERE',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
            'x-organization-id' => '{YOUR_ORGANIZATION_ID}',
        ],
        'query' => [
            'page' => '1',
            'per_page' => '20',
            'document_type' => 'sales',
            'category_type' => 'commercial_expenses',
            'enabled' => '1',
            'editable' => '1',
            'search' => 'Alimentación',
            'filter[document_type]' => 'purchases',
            'filter[category_type]' => 'personal_expenses',
            'filter[search]' => 'vmqeopfuudtdsufvyvddq',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
import requests
import json

url = 'https://ec-demo.taxo.co/api/v1/taxpayers/1726051285001/categories'
params = {
  'page': '1',
  'per_page': '20',
  'document_type': 'sales',
  'category_type': 'commercial_expenses',
  'enabled': '1',
  'editable': '1',
  'search': 'Alimentación',
  'filter[document_type]': 'purchases',
  'filter[category_type]': 'personal_expenses',
  'filter[search]': 'vmqeopfuudtdsufvyvddq',
}
headers = {
  'x-api-key': 'YOUR_API_KEY_HERE',
  'Content-Type': 'application/json',
  'Accept': 'application/json',
  'x-organization-id': '{YOUR_ORGANIZATION_ID}'
}

response = requests.request('GET', url, headers=headers, params=params)
response.json()

Example response (200, Success):


{
    "status": "success",
    "message": "Categories retrieved successfully",
    "data": {
        "categories": [
            {
                "id": 9857,
                "name": "Alimentación",
                "code": "D-001",
                "description": null,
                "icon": "M20 10a5.27...",
                "color": "bg-teal-500",
                "document_type": "purchases",
                "category_type": "personal_expenses",
                "editable": false,
                "has_been_edited": false,
                "enabled": true,
                "created_at": "2024-01-15T10:30:00.000000Z",
                "updated_at": "2024-01-15T10:30:00.000000Z",
                "archived_at": null
            }
        ]
    },
    "meta": {
        "pagination": {
            "total": 30,
            "count": 20,
            "per_page": 20,
            "current_page": 1,
            "total_pages": 2
        },
        "filters": {
            "document_type": "purchases",
            "enabled": true
        }
    }
}
 

Example response (401, Unauthorized):


{
    "status": "error",
    "message": "Invalid API key or organization ID",
    "code": "UNAUTHORIZED"
}
 

Example response (404, Taxpayer not found):


{
    "status": "error",
    "message": "Taxpayer not found or access denied",
    "code": "TAXPAYER_NOT_FOUND"
}
 

Example response (500, Server error):


{
    "status": "error",
    "message": "Failed to retrieve categories. Please try again later.",
    "code": "SERVER_ERROR"
}
 

Request      

GET api/v1/taxpayers/{taxNumber}/categories

Headers

x-api-key        

Example: YOUR_API_KEY_HERE

Content-Type        

Example: application/json

Accept        

Example: application/json

x-organization-id        

Example: {YOUR_ORGANIZATION_ID}

URL Parameters

taxNumber   string     

The taxpayer's RUC number (13 digits). Example: 1726051285001

Query Parameters

page   integer  optional    

Page number for pagination. El campo value debe ser al menos 1. Example: 1

per_page   integer  optional    

Number of items per page (max 100). El campo value debe ser al menos 1. El campo value no debe ser mayor que 100. Example: 20

document_type   string  optional    

Filter by document type (purchases or sales). Example: sales

Must be one of:
  • purchases
  • sales
category_type   string  optional    

Filter by category type (personal_expenses, commercial_expenses, non_deductible_expenses, sales). Example: commercial_expenses

Must be one of:
  • personal_expenses
  • commercial_expenses
  • non_deductible_expenses
  • sales
enabled   string  optional    

Filter by enabled status (1 or 0). Example: 1

editable   string  optional    

Filter by editable status (1 or 0). Example: 1

search   string  optional    

Search term to filter by name, code, or description. El campo value no debe ser mayor que 255 caracteres. Example: Alimentación

filter   object  optional    
filter.document_type   string  optional    

Example: purchases

Must be one of:
  • purchases
  • sales
filter.category_type   string  optional    

Example: personal_expenses

Must be one of:
  • personal_expenses
  • commercial_expenses
  • non_deductible_expenses
  • sales
filter.enabled   string  optional    
filter.editable   string  optional    
filter.search   string  optional    

El campo value no debe ser mayor que 255 caracteres. Example: vmqeopfuudtdsufvyvddq