Skip to main content
POST
/
api
/
v1
/
consulta-cpe
/
masivo
Bulk Document Query
curl --request POST \
  --url https://api.example.com/api/v1/consulta-cpe/masivo \
  --header 'Content-Type: application/json' \
  --data '
{
  "company_id": 123,
  "tipo_documento": "<string>",
  "fecha_desde": "<string>",
  "fecha_hasta": "<string>",
  "limit": 123
}
'
{
  "200": {},
  "422": {},
  "500": {},
  "success": true,
  "message": "<string>",
  "data": {
    "data.total_procesados": 123,
    "data.exitosos": 123,
    "data.fallidos": 123,
    "data.resultados": [
      {
        "data.resultados[].documento_id": 123,
        "data.resultados[].serie_correlativo": "<string>",
        "data.resultados[].resultado": {
          "data.resultados[].resultado.success": true,
          "data.resultados[].resultado.message": "<string>",
          "data.resultados[].resultado.data": {},
          "data.resultados[].resultado.comprobante_codigo": "<string>",
          "data.resultados[].resultado.metodo": "<string>"
        }
      }
    ]
  }
}
Query the status of multiple electronic documents (invoices, boletas, credit notes, or debit notes) in a single request. This endpoint retrieves validation status from SUNAT for documents within a specified date range, with automatic rate limiting to comply with SUNAT’s service requirements.

Authentication

This endpoint requires authentication using Laravel Sanctum. Include the bearer token in the Authorization header:
Authorization: Bearer {your-api-token}

Endpoint

POST /api/v1/consulta-cpe/masivo

Request Body

company_id
integer
required
The ID of the company whose documents will be queried. Must exist in the companies table.
tipo_documento
string
required
The type of document to query. Valid values:
  • 01: Invoices (Facturas)
  • 03: Sales receipts (Boletas)
  • 07: Credit notes (Notas de Crédito)
  • 08: Debit notes (Notas de Débito)
fecha_desde
string
required
Start date for the query range in Y-m-d format (e.g., 2026-03-01)
fecha_hasta
string
required
End date for the query range in Y-m-d format (e.g., 2026-03-31). Must be equal to or after fecha_desde.
limit
integer
default:"50"
Maximum number of documents to query. Valid range: 1-100. Defaults to 50 if not specified.

Response

success
boolean
required
Indicates if the bulk query operation was successful
message
string
required
Human-readable message describing the result
data
object
required
Contains bulk query statistics and individual results
data.total_procesados
integer
Total number of documents processed in the query
data.exitosos
integer
Number of successful queries
data.fallidos
integer
Number of failed queries
data.resultados
array
Array of individual query results for each document
data.resultados[].documento_id
integer
Internal ID of the queried document
data.resultados[].serie_correlativo
string
Document identifier in format “SERIES-CORRELATIVE” (e.g., “F001-00000123”)
data.resultados[].resultado
object
Query result for this specific document
data.resultados[].resultado.success
boolean
Whether the query for this document was successful
data.resultados[].resultado.message
string
Result message for this document
data.resultados[].resultado.data
object
SUNAT query data (same structure as individual query endpoints)
data.resultados[].resultado.comprobante_codigo
string
Document code in format “SERIES-CORRELATIVE”
data.resultados[].resultado.metodo
string
Query method used: api_oauth2 or soap_sol

Code Examples

curl -X POST https://api.yourdomain.com/api/v1/consulta-cpe/masivo \
  -H "Authorization: Bearer {your-api-token}" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "company_id": 1,
    "tipo_documento": "01",
    "fecha_desde": "2026-03-01",
    "fecha_hasta": "2026-03-31",
    "limit": 25
  }'

Response Examples

Success Response (200)

{
  "success": true,
  "message": "Consulta masiva completada",
  "data": {
    "total_procesados": 15,
    "exitosos": 13,
    "fallidos": 2,
    "resultados": [
      {
        "documento_id": 123,
        "serie_correlativo": "F001-00000456",
        "resultado": {
          "success": true,
          "message": "Consulta realizada correctamente",
          "data": {
            "estadocpe": "1",
            "estado_ruc": "ACTIVO",
            "condicion_domicilio": "HABIDO",
            "ubigeo": "150101",
            "descripcion_estado": "Aceptado",
            "consulta_fecha": "2026-03-05 16:20:15"
          },
          "comprobante_codigo": "F001-00000456",
          "metodo": "api_oauth2"
        }
      },
      {
        "documento_id": 124,
        "serie_correlativo": "F001-00000457",
        "resultado": {
          "success": true,
          "message": "Consulta realizada correctamente",
          "data": {
            "estadocpe": "1",
            "estado_ruc": "ACTIVO",
            "condicion_domicilio": "HABIDO",
            "ubigeo": "150101",
            "descripcion_estado": "Aceptado",
            "consulta_fecha": "2026-03-05 16:20:16"
          },
          "comprobante_codigo": "F001-00000457",
          "metodo": "api_oauth2"
        }
      },
      {
        "documento_id": 125,
        "serie_correlativo": "F001-00000458",
        "resultado": {
          "success": false,
          "message": "El comprobante no existe en los registros de SUNAT",
          "data": null
        }
      }
    ]
  }
}

Empty Result (200)

{
  "success": true,
  "message": "No se encontraron documentos en el rango especificado",
  "data": []
}

Validation Error (422)

{
  "message": "The fecha hasta field must be a date after or equal to fecha desde.",
  "errors": {
    "fecha_hasta": [
      "The fecha hasta field must be a date after or equal to fecha desde."
    ]
  }
}

Invalid Document Type (422)

{
  "message": "The selected tipo documento is invalid.",
  "errors": {
    "tipo_documento": [
      "The selected tipo documento is invalid."
    ]
  }
}

Server Error (500)

{
  "success": false,
  "message": "Error en consulta masiva",
  "error": "Database connection lost"
}

Status Codes

200
OK
Bulk query completed. Check individual results for per-document status.
422
Unprocessable Entity
Validation error in request parameters
500
Internal Server Error
Server error occurred during bulk query processing

Document Selection Criteria

The endpoint queries documents that match ALL of the following criteria:
  1. Belong to the specified company (company_id)
  2. Match the specified document type (tipo_documento)
  3. Have an issue date (fecha_emision) within the specified range
  4. Have a SUNAT status of ACEPTADO, RECHAZADO, or NULL
  5. Ordered by issue date (most recent first)
  6. Limited to the specified number of documents (max 100)
Documents with status ACEPTADO, RECHAZADO, or NULL are included because they may need status verification. Documents with other statuses are excluded from bulk queries.

Rate Limiting and Performance

To protect SUNAT services and ensure reliable operation:
  • Automatic Delay: 0.5 seconds (500ms) between each query
  • Maximum Documents: 100 per request
  • Default Limit: 50 documents if not specified
  • Token Caching: OAuth2 tokens are cached for 45 minutes
  • Fallback Support: Automatically switches to SOAP SOL if OAuth2 fails
Processing time estimate: For 50 documents, expect approximately 25-30 seconds due to the 0.5-second delay between queries plus network latency.

Use Cases

Daily Status Verification

{
  "company_id": 1,
  "tipo_documento": "01",
  "fecha_desde": "2026-03-05",
  "fecha_hasta": "2026-03-05",
  "limit": 100
}
Query all invoices issued today to verify their acceptance status.

Monthly Reconciliation

{
  "company_id": 1,
  "tipo_documento": "03",
  "fecha_desde": "2026-02-01",
  "fecha_hasta": "2026-02-28",
  "limit": 100
}
Query all boletas from the previous month for accounting reconciliation.

Multi-Document Type Queries

To query multiple document types, make separate requests:
const documentTypes = ['01', '03', '07', '08'];
const results = {};

for (const tipo of documentTypes) {
  const response = await fetch('/api/v1/consulta-cpe/masivo', {
    method: 'POST',
    headers: { /* ... */ },
    body: JSON.stringify({
      company_id: 1,
      tipo_documento: tipo,
      fecha_desde: '2026-03-01',
      fecha_hasta: '2026-03-31',
      limit: 50
    })
  });
  
  results[tipo] = await response.json();
}

Database Updates

For each successfully queried document, the following fields are updated:
  • consulta_cpe_estado: CPE status code from SUNAT
  • consulta_cpe_respuesta: Full JSON response from SUNAT
  • consulta_cpe_fecha: Timestamp when the query was performed
  • estado_sunat: Current SUNAT status
Failed queries do not update the database. Only successful queries with valid responses from SUNAT will update document records.

Implementation Details

The bulk query process (app/Services/ConsultaCpeService.php:352):
  1. Validate request parameters (company, document type, date range, limit)
  2. Retrieve documents matching the criteria from the appropriate table
  3. Return empty result if no documents found
  4. For each document:
    • Query SUNAT using consultarComprobante() method
    • Record success/failure
    • Wait 0.5 seconds before next query
  5. Return aggregated results with statistics

Best Practices

For Real-time Queries: Use individual query endpoints (/factura/{id} or /boleta/{id})For Batch Processing: Use this bulk endpoint with appropriate limitsFor Large Datasets: Split into multiple requests with smaller date ranges
  • Small batches (1-10 docs): Real-time, immediate results
  • Medium batches (11-50 docs): Background jobs, expect 30-60 seconds
  • Large batches (51-100 docs): Async processing, expect 1-2 minutes

Error Handling

Individual document failures don’t stop the bulk process. Check:
  1. Overall success flag
  2. exitosos vs fallidos counts
  3. Individual resultado.success for each document
if (data.success) {
  console.log(`Processed: ${data.data.total_procesados}`);
  console.log(`Success: ${data.data.exitosos}, Failed: ${data.data.fallidos}`);
  
  // Check individual failures
  data.data.resultados.forEach(doc => {
    if (!doc.resultado.success) {
      console.error(`Failed: ${doc.serie_correlativo}`);
      console.error(`Reason: ${doc.resultado.message}`);
    }
  });
}

Build docs developers (and LLMs) love