FEL Backend API - cURL Test Examples
This document provides cURL commands for testing the FEL Backend API endpoints for Credit Notes, Debit Notes, and Cancellations.
Prerequisites
- Backend Server: Ensure the backend is running (default:
http://localhost:4000) - Authentication Token: Get a Firebase ID token from:
- Browser DevTools: Application > Cookies >
firebase-id-token - Or use Firebase CLI:
firebase auth:export - Or extract from your frontend application's authentication state
- Browser DevTools: Application > Cookies >
- Valid UUIDs: You'll need valid UUIDs from your database:
- Business ID
- Sale ID (certified invoice)
- User ID
- Location ID
- Customer ID
- Currency ID
- Original Invoice UUID (FEL UUID from
sale.felNumberorsale.felUuid)
Base Configuration
Set these variables before running commands:
export BASE_URL="http://localhost:4000"
export TOKEN="YOUR_FIREBASE_ID_TOKEN_HERE"
export BUSINESS_ID="your-business-uuid"
export SALE_ID="your-certified-sale-uuid"
export USER_ID="your-user-uuid"
export LOCATION_ID="your-location-uuid"
export CUSTOMER_ID="your-customer-uuid"
export CURRENCY_ID="your-currency-uuid"
export ORIGINAL_INVOICE_UUID="fel-uuid-from-certified-sale"
Credit Note Endpoints
1. Create Credit Note
POST /fel/credit-notes
curl -X POST "${BASE_URL}/fel/credit-notes" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"businessId": "'"${BUSINESS_ID}"'",
"saleId": "'"${SALE_ID}"'",
"createdBy": "'"${USER_ID}"'",
"creditNoteDate": "2024-01-15T10:00:00.000Z",
"customerId": "'"${CUSTOMER_ID}"'",
"taxId": "12345678-9",
"taxName": "Cliente de Prueba",
"taxAddress": "Ciudad de Guatemala",
"locationId": "'"${LOCATION_ID}"'",
"locationName": "Tienda Principal",
"currencyId": "'"${CURRENCY_ID}"'",
"currencyCode": "GTQ",
"minorUnit": 2,
"exchangeRate": 1.0,
"currency": {
"id": "'"${CURRENCY_ID}"'",
"code": "GTQ",
"name": "Quetzal",
"symbol": "Q"
},
"totalAmount": 100.00,
"totalBaseAmount": 90.00,
"detail": {
"items": [
{
"productId": "product-uuid",
"productName": "Producto de Prueba",
"quantity": 1,
"unitPrice": 100.00,
"amount": 100.00,
"baseAmount": 90.00,
"taxes": [
{
"taxId": "tax-uuid",
"taxName": "IVA",
"rate": 0.12,
"amount": 10.00,
"baseAmount": 90.00
}
]
}
]
},
"paymentDetail": {},
"taxpayerType": "NIT",
"originalInvoiceUuid": "'"${ORIGINAL_INVOICE_UUID}"'",
"adjustmentReason": "Devolución de mercancía",
"generateElectronicTaxDocument": true
}'
Response: Returns the created credit note object with id field.
2. Get Credit Note by ID
GET /fel/credit-notes/:id
curl -X GET "${BASE_URL}/fel/credit-notes/YOUR_CREDIT_NOTE_ID" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json"
3. Get Credit Notes by Sale ID
GET /fel/credit-notes/sale/:saleId
curl -X GET "${BASE_URL}/fel/credit-notes/sale/${SALE_ID}" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json"
Response: Returns an array of credit notes for the given sale.
4. Certify Credit Note
POST /fel/credit-notes/:id/certify
curl -X POST "${BASE_URL}/fel/credit-notes/YOUR_CREDIT_NOTE_ID/certify" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json"
Note: This endpoint will:
- Validate the credit note meets SAT requirements
- Convert it to DTE JSON format
- Send it to RPAfelApi for certification
- Update the credit note with certification details
- Trigger inventory reversal via event handler
Debit Note Endpoints
1. Create Debit Note
POST /fel/debit-notes
curl -X POST "${BASE_URL}/fel/debit-notes" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"businessId": "'"${BUSINESS_ID}"'",
"saleId": "'"${SALE_ID}"'",
"createdBy": "'"${USER_ID}"'",
"debitNoteDate": "2024-01-15T10:00:00.000Z",
"customerId": "'"${CUSTOMER_ID}"'",
"taxId": "12345678-9",
"taxName": "Cliente de Prueba",
"taxAddress": "Ciudad de Guatemala",
"locationId": "'"${LOCATION_ID}"'",
"locationName": "Tienda Principal",
"currencyId": "'"${CURRENCY_ID}"'",
"currencyCode": "GTQ",
"minorUnit": 2,
"exchangeRate": 1.0,
"currency": {
"id": "'"${CURRENCY_ID}"'",
"code": "GTQ",
"name": "Quetzal",
"symbol": "Q"
},
"totalAmount": 50.00,
"totalBaseAmount": 45.00,
"detail": {
"items": [
{
"productId": "product-uuid",
"productName": "Producto de Prueba",
"quantity": 1,
"unitPrice": 50.00,
"amount": 50.00,
"baseAmount": 45.00,
"taxes": [
{
"taxId": "tax-uuid",
"taxName": "IVA",
"rate": 0.12,
"amount": 5.00,
"baseAmount": 45.00
}
]
}
]
},
"paymentDetail": {},
"taxpayerType": "NIT",
"originalInvoiceUuid": "'"${ORIGINAL_INVOICE_UUID}"'",
"adjustmentReason": "Ajuste por error en facturación",
"generateElectronicTaxDocument": true
}'
2. Get Debit Note by ID
GET /fel/debit-notes/:id
curl -X GET "${BASE_URL}/fel/debit-notes/YOUR_DEBIT_NOTE_ID" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json"
3. Get Debit Notes by Sale ID
GET /fel/debit-notes/sale/:saleId
curl -X GET "${BASE_URL}/fel/debit-notes/sale/${SALE_ID}" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json"
4. Certify Debit Note
POST /fel/debit-notes/:id/certify
curl -X POST "${BASE_URL}/fel/debit-notes/YOUR_DEBIT_NOTE_ID/certify" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json"
Cancellation Endpoints
1. Request Cancellation
POST /fel/cancellations
curl -X POST "${BASE_URL}/fel/cancellations" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"saleId": "'"${SALE_ID}"'",
"cancellationReason": "Error en la facturación",
"createdBy": "'"${USER_ID}"'"
}'
Response: Returns the created cancellation object with id field.
Note: The cancellation reason must follow SAT requirements (e.g., same-month cancellation only).
2. Get Cancellation by ID
GET /fel/cancellations/:id
curl -X GET "${BASE_URL}/fel/cancellations/YOUR_CANCELLATION_ID" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json"
3. Get Cancellations by Sale ID
GET /fel/cancellations/sale/:saleId
curl -X GET "${BASE_URL}/fel/cancellations/sale/${SALE_ID}" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json"
Response: Returns an array of cancellations for the given sale.
4. Certify Cancellation
POST /fel/cancellations/:id/certify
curl -X POST "${BASE_URL}/fel/cancellations/YOUR_CANCELLATION_ID/certify" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json"
Note: This endpoint will:
- Validate the cancellation meets SAT requirements
- Convert it to DTE JSON format
- Send it to RPAfelApi for certification
- Update the cancellation with certification details
- Update the sale status to
CANCELLED - Trigger inventory reversal via event handler
Testing Workflow
Complete Credit Note Flow
- Create Credit Note → Get
creditNoteId - Get Credit Note → Verify it was created correctly
- Certify Credit Note → Verify certification and inventory reversal
Complete Debit Note Flow
- Create Debit Note → Get
debitNoteId - Get Debit Note → Verify it was created correctly
- Certify Debit Note → Verify certification
Complete Cancellation Flow
- Request Cancellation → Get
cancellationId - Get Cancellation → Verify it was created correctly
- Certify Cancellation → Verify certification, sale status update, and inventory reversal
Common Validation Errors
Credit Note / Debit Note
- Original Invoice UUID not found: Ensure the sale has been certified and has a valid FEL UUID
- Credit note amount exceeds original: Credit note total cannot exceed original invoice total
- Adjustment reason required: Must provide a valid SAT adjustment reason
Cancellation
- Cancellation outside same month: Can only cancel invoices in the same month they were issued
- Sale already cancelled: Cannot cancel an already cancelled sale
- Cancellation reason required: Must provide a valid SAT cancellation reason
Getting Required Data from Database
Get a Certified Sale (Invoice)
# Query your database for a certified sale
# Look for: sale.status = 'certified' AND sale.felNumber IS NOT NULL
# Extract: id, felNumber (originalInvoiceUuid), businessId, etc.
Get Original Invoice UUID
The originalInvoiceUuid should be the FEL UUID from the certified sale:
- Check
sale.felNumberfield (this is typically the FEL UUID) - Or check
sale.felUuidif that field exists
Example: Using jq to Extract IDs
If you have jq installed, you can extract IDs from responses:
# Create credit note and extract ID
CREDIT_NOTE_RESPONSE=$(curl -X POST "${BASE_URL}/fel/credit-notes" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d @credit-note-payload.json)
CREDIT_NOTE_ID=$(echo "$CREDIT_NOTE_RESPONSE" | jq -r '.id')
echo "Credit Note ID: $CREDIT_NOTE_ID"
# Now use it to certify
curl -X POST "${BASE_URL}/fel/credit-notes/${CREDIT_NOTE_ID}/certify" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json"
Using the Test Script
A bash script is available at docs/fel/backend-api-test-curl-commands.sh:
# Make it executable
chmod +x docs/fel/backend-api-test-curl-commands.sh
# Edit the script to set your variables
# Then run it
./docs/fel/backend-api-test-curl-commands.sh
Troubleshooting
401 Unauthorized
- Check that your Firebase ID token is valid and not expired
- Verify the token is being sent correctly in the Authorization header
404 Not Found
- Ensure the backend server is running
- Check that the endpoint path is correct (
/fel/...)
400 Bad Request
- Check that all required fields are present in the request body
- Verify UUID formats are correct
- Check that the sale exists and is certified (for credit/debit notes)
500 Internal Server Error
- Check backend logs for detailed error messages
- Verify database connections and that migrations have been run
- Ensure RPAfelApi credentials are configured if testing certification