Overview

e-Factura is Romania’s electronic invoicing system managed by ANAF (National Agency for Fiscal Administration). All invoices (both B2B and B2C) must be reported to the SPV (Spațiul Privat Virtual) platform. Contazen provides seamless integration with the e-Factura system, handling the OAuth2 authentication, XML generation, and submission processes automatically.

Prerequisites

Before using e-Factura features through the API, ensure your account is properly configured:
  1. ANAF OAuth2 Setup: Complete the OAuth2 authorization flow in your Contazen dashboard
  2. Environment Selection: Choose between test (sandbox) or live (production) mode
  3. Proper Firm Registration: Ensure your firm details (CUI, address, etc.) are accurate

Setup Process

1. Check e-Factura Status

First, verify your e-Factura configuration using the Settings endpoint:
curl -X GET "https://api.contazen.ro/v1/settings" \
  -H "Authorization: Bearer your_api_key_here"

2. e-Factura Settings Response

The settings response includes comprehensive e-Factura status information:
{
  "success": true,
  "data": {
    "efactura": {
      "enabled": true,
      "oauth_configured": true,
      "test_mode_available": true,
      "live_mode_available": true,
      "oauth_created_at": "2024-01-15T10:30:00Z",
      "oauth_expires_at": "2024-07-15T10:30:00Z",
      "settings": {
        "environment": "test",
        "auto_send": false,
        "auto_send_timing": "immediately",
        "send_to_public_institutions": true
      }
    }
  }
}

3. Manual OAuth Setup

If oauth_configured is false, you’ll need to complete the OAuth setup in the Contazen dashboard before using the API endpoints.

Creating e-Factura Compatible Invoices

Invoice Requirements

For invoices to be eligible for e-Factura submission:
  1. Document Type: Must be fiscal
  2. Client Type: B2B with valid Romanian CUI or B2C (CNP is optional, use - if not available)
  3. Complete Data: All required fields must be present
  4. Status: Invoice must be finalized (not draft)
  5. UBL Compliance: Items should include proper UBL unit codes

UBL Unit Codes for e-Factura

The Romanian e-Factura system requires UBL (Universal Business Language) unit codes for proper classification. Contazen automatically handles this with intelligent defaults and mappings.

Default Behavior

  • Default Unit: If no ubl_um is specified, defaults to H87 (bucată/piece)
  • Auto-mapping: System maps common Romanian units to UBL codes automatically
  • Validation: Invalid codes generate warnings but don’t block invoice creation
  • e-Factura Status: efactura_enabled defaults to true for fiscal invoices

Common UBL Unit Codes

UBL codes are case-insensitive. Both H87 and h87 work correctly.
CodeDescriptionRomanianBest Used For
H87Piece/ItembucatăPhysical products, default
HURHourorăTime-based services
DAYDayziDaily rates, rentals
MONMonthlunăMonthly subscriptions
ANNYearanAnnual licenses
KGMKilogramkilogramWeight-based products
MTRMetermetruLength measurements
LTRLiterlitruLiquids, chemicals
KMTKilometerkilometruTransport, delivery

Example Invoice Creation

Basic Invoice with UBL Units

// B2B Invoice Example
const b2bInvoiceData = {
  client_data: {
    type: "b2b",
    name: "Example SRL",
    cui: "RO12345678",
    address: "Str. Exemplu Nr. 1",
    city: "București",
    county: "București",
    email: "contact@example.com"
  },
  items: [
    {
      description: "Servicii consultanță IT",
      quantity: 10,
      price: 150.00,
      vat_rate: 19,
      unit: "ore",
      ubl_um: "HUR"  // UBL code for hours
    }
  ],
  document_type: "fiscal",
  efactura_enabled: true,
  observations: "Factură pentru servicii IT"
};

const response = await fetch('https://api.contazen.ro/v1/invoices', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer your_api_key_here',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(b2bInvoiceData)
});

const invoice = await response.json();
console.log('Invoice created:', invoice.data.id);

// B2C Invoice Example
const b2cInvoiceData = {
  client_data: {
    type: "b2c",
    name: "Ion Popescu",
    cnp: "1234567890123", // Optional - use "-" if not available
    address: "Str. Exemplu Nr. 1",
    city: "București",
    county: "București",
    email: "ion.popescu@example.com"
  },
  items: [
    {
      description: "Produs electronic",
      quantity: 1,
      price: 500.00,
      vat_rate: 19,
      unit: "buc",
      ubl_um: "H87"
    }
  ],
  document_type: "fiscal",
  efactura_enabled: true
};

Advanced e-Factura Compliance

For full e-Factura compliance, include additional UBL classification codes:
const advancedInvoiceData = {
  client_data: {
    type: "b2b",
    name: "Tech Solutions SRL",
    cui: "RO98765432",
    address: "Bd. Magheru Nr. 15",
    city: "București",
    county: "București"
  },
  items: [
    {
      description: "Laptop DELL XPS 15",
      quantity: 2,
      price: 5000.00,
      vat_rate: 19,
      unit: "bucăți",
      ubl_um: "H87",              // UBL unit: piece
      ubl_nc: "84713000",         // Combined Nomenclature code
      ubl_cpv: "30213100-6",      // Common Procurement Vocabulary
      vat_key: "S"                // Standard VAT rate classification
    },
    {
      description: "Installation and setup service",
      quantity: 8,
      price: 200.00,
      vat_rate: 19,
      unit: "ore",
      ubl_um: "HUR",              // UBL unit: hour
      ubl_cpv: "72253000-3"       // CPV for computer support services
    }
  ],
  document_type: "fiscal",
  efactura_enabled: true
};

const response = await fetch('https://api.contazen.ro/v1/invoices', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer your_api_key_here',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(advancedInvoiceData)
});

UBL Field Reference

When creating invoice items for e-Factura, you can include these UBL-related fields:
FieldTypeRequiredDescriptionExample
unitstringNoHuman-readable unit name"ore", "bucăți", "kg"
ubl_umstringNoUBL unit code for e-Factura"HUR", "H87", "KGM"
ubl_ncstringNoCombined Nomenclature code"84713000"
ubl_cpvstringNoCommon Procurement Vocabulary"30213100-6"
vat_keystringNoVAT classification key"S", "E", "O"
Auto-mapping: If you only provide unit (e.g., “ore”), Contazen automatically maps it to the correct UBL code (HUR). The system includes pre-configured mappings for common Romanian units.

UBL Validation Rules

UBL Resources and References

Quick Start: For most use cases, you only need ubl_um. The system will handle the rest automatically. Use HUR for time-based services and H87 for physical products.

Sending Invoices to SPV

Basic SPV Submission

Once you have a fiscal invoice, submit it to the e-Factura system:
curl -X POST "https://api.contazen.ro/v1/invoices/inv_1a2b3c4d5e/send-to-spv" \
  -H "Authorization: Bearer your_api_key_here" \
  -H "Content-Type: application/json"

Environment Override

You can override the default environment (test/live) for specific submissions:
curl -X POST "https://api.contazen.ro/v1/invoices/inv_1a2b3c4d5e/send-to-spv?environment=live" \
  -H "Authorization: Bearer your_api_key_here"

Successful Response

{
  "success": true,
  "data": {
    "object": "efactura_submission",
    "submission_id": "spv_abc123def456",
    "status": "submitted",
    "submitted_at": "2024-01-20T14:30:00Z",
    "environment": "test"
  }
}

Tracking Submission Status

Using Expand Parameter

Retrieve invoice details with e-Factura status:
curl -X GET "https://api.contazen.ro/v1/invoices/inv_1a2b3c4d5e?expand[]=efactura" \
  -H "Authorization: Bearer your_api_key_here"

Response with e-Factura Status

{
  "success": true,
  "data": {
    "id": "inv_1a2b3c4d5e",
    "number": "CTZ-2024-00001",
    "status": "sent",
    "efactura": {
      "object": "efactura_submission",
      "submission_id": "spv_abc123def456",
      "status": "submitted",
      "submitted_at": "2024-01-20T14:30:00Z",
      "environment": "test",
      "response_data": {
        "index_incarcare": "123456789"
      }
    }
  }
}

Voiding e-Factura Invoices

Standard Void Process

When voiding an invoice that was sent to e-Factura, the system automatically sends a cancellation message to ANAF:
curl -X POST "https://api.contazen.ro/v1/invoices/inv_1a2b3c4d5e/void" \
  -H "Authorization: Bearer your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Eroare în date client",
    "void_date": "2024-01-20"
  }'

Void Response

{
  "success": true,
  "data": {
    "id": "inv_1a2b3c4d5e",
    "status": "cancelled",
    "void_reason": "Eroare în date client",
    "void_date": "2024-01-20",
    "efactura": {
      "status": "cancelled",
      "cancellation_sent": true
    }
  }
}

Error Handling

Common e-Factura Errors

OAuth Not Configured

Error Code: efactura_oauth_not_configuredSolution: Complete OAuth setup in dashboard before using API endpoints.

Already Sent to SPV

Error Code: already_sent_to_spvSolution: Check invoice status before attempting submission.

Invalid Document Type

Error Code: invalid_document_typeSolution: Only fiscal invoices can be sent to e-Factura.

Draft Invoice

Error Code: invoice_is_draftSolution: Finalize the invoice before submitting to SPV.

Error Response Example

{
  "success": false,
  "error": {
    "message": "e-Factura OAuth not configured",
    "type": "invalid_request_error",
    "code": "efactura_oauth_not_configured",
    "status": 400
  }
}

Retry Logic for Failures

Implement retry logic for temporary failures:
async function submitToSpvWithRetry(invoiceId, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(`https://api.contazen.ro/v1/invoices/${invoiceId}/send-to-spv`, {
        method: 'POST',
        headers: {
          'Authorization': 'Bearer your_api_key_here',
          'Content-Type': 'application/json'
        }
      });
      
      const result = await response.json();
      
      if (result.success) {
        return result;
      }
      
      // Don't retry client errors
      if (response.status >= 400 && response.status < 500) {
        throw new Error(result.error.message);
      }
      
      // Retry server errors
      if (i < maxRetries - 1) {
        await sleep(Math.pow(2, i) * 1000); // Exponential backoff
      }
      
    } catch (error) {
      if (i === maxRetries - 1) throw error;
    }
  }
}

Best Practices

1. Environment Management

  • Development: Always start with test environment
  • Production: Switch to live only after thorough testing
  • Token Management: Monitor OAuth token expiration dates

2. Error Handling

async function createAndSubmitInvoice(invoiceData) {
  try {
    // Create invoice
    const invoice = await createInvoice(invoiceData);
    
    // Check if eligible for e-Factura
    if (invoice.data.document_type === 'fiscal') {
      
      // Submit to SPV
      const submission = await submitToSpv(invoice.data.id);
      
      return {
        invoice: invoice.data,
        efactura: submission.data
      };
    }
    
    return { invoice: invoice.data };
    
  } catch (error) {
    console.error('Invoice creation/submission failed:', error.message);
    
    // Handle specific error types
    if (error.code === 'efactura_oauth_not_configured') {
      throw new Error('Please configure e-Factura OAuth in dashboard');
    }
    
    throw error;
  }
}

3. Batch Processing

For multiple invoices, implement proper rate limiting:
async function submitMultipleInvoices(invoiceIds) {
  const results = [];
  
  for (const invoiceId of invoiceIds) {
    try {
      const result = await submitToSpv(invoiceId);
      results.push({ invoiceId, success: true, data: result.data });
      
      // Rate limiting - wait between submissions
      await sleep(1000);
      
    } catch (error) {
      results.push({ invoiceId, success: false, error: error.message });
    }
  }
  
  return results;
}

4. Status Monitoring

Regularly check submission status for long-running processes:
async function monitorSubmissionStatus(invoiceId) {
  const response = await fetch(`https://api.contazen.ro/v1/invoices/${invoiceId}?expand[]=efactura`, {
    headers: { 'Authorization': 'Bearer your_api_key_here' }
  });
  
  const invoice = await response.json();
  const efacturaStatus = invoice.data.efactura;
  
  if (efacturaStatus) {
    console.log(`Invoice ${invoiceId} - SPV Status: ${efacturaStatus.status}`);
    return efacturaStatus.status;
  }
  
  return 'not_submitted';
}

Integration Checklist

1

Configure OAuth

Complete the e-Factura OAuth setup in your Contazen dashboard
2

Test Environment

Start with test environment to validate your integration
3

Create Test Invoice

Create a fiscal invoice with valid Romanian client data
4

Submit to SPV

Test the send-to-spv endpoint with your test invoice
5

Handle Errors

Implement proper error handling for all scenarios
6

Monitor Status

Use the expand parameter to track submission status
7

Production Ready

Switch to live environment when ready for production

Support and Resources

  • Dashboard: Complete OAuth setup at app.contazen.ro
  • ANAF Documentation: Official e-Factura technical documentation
  • Support: Contact contact@contazen.ro for integration help
  • Status Page: Monitor API status and e-Factura system availability

Compliance Notes

  • Mandatory Reporting: All invoices (B2B and B2C) must be reported to SPV
  • Deadlines: Invoices must be submitted within legal deadlines (typically 5 days)
  • Data Accuracy: Ensure all client and invoice data is accurate before submission
  • Record Keeping: Maintain records of all e-Factura submissions for audit purposes
  • B2C Requirements: CNP is optional for B2C clients - use - if not available