# Error Codes

Complete reference of all error codes returned by the Monetarie NPC API.

## Error Response Format

All error responses follow a standardized format:

```json
{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error description",
    "details": "Additional information to resolve the problem"
  },
  "meta": {
    "request_id": "req_abc123def456"
  }
}
```

| Field           | Type   | Description                                    |
|-----------------|--------|----------------------------------------------|
| `success`       | boolean| Always `false` for errors                    |
| `error.code`    | string | Error identifier code (use in logic)         |
| `error.message` | string | Descriptive error message                    |
| `error.details` | string | Additional details or correction suggestions |
| `meta.request_id` | string | Unique request ID (important for support)  |

::: tip Request ID
Always include the `request_id` when contacting support. This allows us to trace your specific request in our logs.
:::

---

## Authentication Errors (401)

Errors related to API Key authentication.

### MISSING_API_KEY

The `X-API-Key` header was not included in the request.

```json
{
  "success": false,
  "error": {
    "code": "MISSING_API_KEY",
    "message": "The X-API-Key header is required",
    "details": "Include your API Key in the X-API-Key header of the request"
  },
  "meta": {
    "request_id": "req_abc123def456"
  }
}
```

**How to resolve:** Add the `X-API-Key` header with your API key.

### INVALID_API_KEY

The provided API Key is invalid or does not exist.

```json
{
  "success": false,
  "error": {
    "code": "INVALID_API_KEY",
    "message": "Invalid or expired API Key",
    "details": "Verify that the key is correct and active in the portal"
  },
  "meta": {
    "request_id": "req_abc123def456"
  }
}
```

**How to resolve:** Verify that the API Key is correct. Generate a new key in the portal if necessary.

### API_KEY_REVOKED

The API Key has been revoked and can no longer be used.

```json
{
  "success": false,
  "error": {
    "code": "API_KEY_REVOKED",
    "message": "This API Key has been revoked",
    "details": "Generate a new key in the portal or contact support"
  },
  "meta": {
    "request_id": "req_abc123def456"
  }
}
```

**How to resolve:** Access the Monetarie Portal and generate a new API Key.

---

## Authorization Errors (403)

Errors related to permissions and access.

### FORBIDDEN

The API Key does not have permission to access this resource.

```json
{
  "success": false,
  "error": {
    "code": "FORBIDDEN",
    "message": "Access denied to this resource",
    "details": "Your API Key does not have permission for this operation"
  },
  "meta": {
    "request_id": "req_abc123def456"
  }
}
```

**How to resolve:** Check your API Key permissions in the portal or contact support.

### IP_NOT_ALLOWED

The request was made from an unauthorized IP.

```json
{
  "success": false,
  "error": {
    "code": "IP_NOT_ALLOWED",
    "message": "IP not authorized",
    "details": "IP 203.0.113.50 is not in the allowed IP list"
  },
  "meta": {
    "request_id": "req_abc123def456"
  }
}
```

**How to resolve:** Add the source IP to the allowed IP list in the portal.

---

## Validation Errors (400/422)

Errors related to invalid data in the request.

### VALIDATION_ERROR

One or more request fields are invalid.

```json
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid data in request",
    "details": {
      "amount_cents": ["must be greater than 0"],
      "due_date": ["must be a future date"],
      "payer_document": ["invalid format"]
    }
  },
  "meta": {
    "request_id": "req_abc123def456"
  }
}
```

**How to resolve:** Correct the fields indicated in the `details` object.

### INVALID_DOCUMENT

The document (CPF/CNPJ) provided is invalid.

```json
{
  "success": false,
  "error": {
    "code": "INVALID_DOCUMENT",
    "message": "Invalid document",
    "details": "The CPF/CNPJ '12345678900' does not have valid check digits"
  },
  "meta": {
    "request_id": "req_abc123def456"
  }
}
```

**How to resolve:** Verify that the CPF or CNPJ is correct, including check digits.

### INVALID_DUE_DATE

The due date is invalid or in the past.

```json
{
  "success": false,
  "error": {
    "code": "INVALID_DUE_DATE",
    "message": "Invalid due date",
    "details": "The due date must be equal to or later than the current date"
  },
  "meta": {
    "request_id": "req_abc123def456"
  }
}
```

**How to resolve:** Use a future due date in `YYYY-MM-DD` format.

### AMOUNT_TOO_LOW

The boleto value is less than the allowed minimum.

```json
{
  "success": false,
  "error": {
    "code": "AMOUNT_TOO_LOW",
    "message": "Value too low",
    "details": "The minimum value for a boleto is R$ 1.00 (100 cents)"
  },
  "meta": {
    "request_id": "req_abc123def456"
  }
}
```

**How to resolve:** The minimum value is 100 cents (R$ 1.00).

---

## Resource Errors (404/409)

Errors related to resources not found or conflicts.

### NOT_FOUND

The requested resource was not found.

```json
{
  "success": false,
  "error": {
    "code": "NOT_FOUND",
    "message": "Resource not found",
    "details": "The requested resource does not exist or has been removed"
  },
  "meta": {
    "request_id": "req_abc123def456"
  }
}
```

### BOLETO_NOT_FOUND

The specified boleto was not found.

```json
{
  "success": false,
  "error": {
    "code": "BOLETO_NOT_FOUND",
    "message": "Boleto not found",
    "details": "No boleto found with nosso_numero '12345678901'"
  },
  "meta": {
    "request_id": "req_abc123def456"
  }
}
```

**How to resolve:** Verify that the `nosso_numero` is correct.

### DUPLICATE_BOLETO

A boleto with the same `nosso_numero` already exists.

```json
{
  "success": false,
  "error": {
    "code": "DUPLICATE_BOLETO",
    "message": "Duplicate boleto",
    "details": "A boleto with nosso_numero '12345678901' already exists"
  },
  "meta": {
    "request_id": "req_abc123def456"
  }
}
```

**How to resolve:** Use a unique `nosso_numero` for each boleto.

### INVALID_STATUS_TRANSITION

The requested status transition is not allowed.

```json
{
  "success": false,
  "error": {
    "code": "INVALID_STATUS_TRANSITION",
    "message": "Invalid status transition",
    "details": "Cannot change status from 'paid' to 'cancelled'"
  },
  "meta": {
    "request_id": "req_abc123def456"
  }
}
```

**How to resolve:** Check the status transition diagram below.

### Status Transition Diagram

The boleto lifecycle follows strict transition rules:

```
                    +-----------+
                    |   draft   |
                    +-----+-----+
                          |
                          | register
                          v
                    +-----------+
            +------>| registered|<------+
            |       +-----+-----+       |
            |             |             |
            | cancel      | pay         | cancel
            |             v             |
            |       +-----------+       |
            +-------+   paid    +-------+
                    +-----+-----+
                          |
                          | settle
                          v
                    +-----------+
                    |  settled  |
                    +-----------+

                    +-----------+
                    | cancelled | (final state)
                    +-----------+
```

**Allowed transitions:**

| Current Status | Possible Transitions           |
|---------------|-------------------------------|
| `draft`       | `registered`                  |
| `registered`  | `paid`, `cancelled`           |
| `paid`        | `settled`                     |
| `settled`     | (none - final state)          |
| `cancelled`   | (none - final state)          |

---

## Rate Limit Errors (429)

Errors related to request limits.

### RATE_LIMITED

The request limit has been exceeded.

```json
{
  "success": false,
  "error": {
    "code": "RATE_LIMITED",
    "message": "Request limit exceeded",
    "details": "Wait 45 seconds before making new requests"
  },
  "meta": {
    "request_id": "req_abc123def456"
  }
}
```

**Headers returned:**

| Header                 | Value    | Description                            |
|------------------------|----------|----------------------------------------|
| `X-RateLimit-Limit`    | `100`    | Total request limit                    |
| `X-RateLimit-Remaining`| `0`      | Remaining requests                     |
| `X-RateLimit-Reset`    | `1706968800` | Unix timestamp when limit resets     |
| `Retry-After`          | `45`     | Seconds to wait                        |

**How to resolve:** Wait the time indicated in the `Retry-After` header before trying again.

See the [Rate Limits](/en/reference/rate-limits) page for more details.

---

## Server Errors (500/503)

Internal or unavailability errors.

### INTERNAL_ERROR

Internal server error.

```json
{
  "success": false,
  "error": {
    "code": "INTERNAL_ERROR",
    "message": "Internal server error",
    "details": "An unexpected error occurred. Our team has been notified."
  },
  "meta": {
    "request_id": "req_abc123def456"
  }
}
```

**How to resolve:** Try again in a few minutes. If the problem persists, contact support including the `request_id`.

### PCR_UNAVAILABLE

Nuclea's PCR service is temporarily unavailable.

```json
{
  "success": false,
  "error": {
    "code": "PCR_UNAVAILABLE",
    "message": "PCR service unavailable",
    "details": "Nuclea's boleto registration service is temporarily unavailable"
  },
  "meta": {
    "request_id": "req_abc123def456"
  }
}
```

**How to resolve:** Nuclea's PCR service may be under maintenance. Try again in a few minutes.

### FTP_UNAVAILABLE

Nuclea's FTP service is temporarily unavailable.

```json
{
  "success": false,
  "error": {
    "code": "FTP_UNAVAILABLE",
    "message": "FTP service unavailable",
    "details": "Nuclea's file service is temporarily unavailable"
  },
  "meta": {
    "request_id": "req_abc123def456"
  }
}
```

**How to resolve:** Settlement files are automatically processed when the service normalizes.

---

## Error Handling

### JavaScript Example

```javascript
async function createBoleto(boletoData) {
  try {
    const response = await fetch(
      "https://api.monetarie_npc.com.br/api/v1/central/boletos",
      {
        method: "POST",
        headers: {
          "X-API-Key": process.env.MONETARIE_NPC_API_KEY,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ boleto: boletoData }),
      }
    );

    const data = await response.json();

    if (!response.ok) {
      // Handle specific errors
      switch (data.error.code) {
        case "VALIDATION_ERROR":
          console.error("Invalid data:", data.error.details);
          // Show validation errors to user
          break;

        case "DUPLICATE_BOLETO":
          console.error("Boleto already exists:", data.error.message);
          // Fetch existing boleto
          break;

        case "RATE_LIMITED":
          const retryAfter = response.headers.get("Retry-After");
          console.log(`Waiting ${retryAfter} seconds...`);
          // Implement retry with backoff
          break;

        case "PCR_UNAVAILABLE":
        case "INTERNAL_ERROR":
          console.error("Server error:", data.error.message);
          // Schedule retry
          break;

        default:
          console.error("Unknown error:", data.error);
      }

      // Log request_id for support
      console.log("Request ID:", data.meta.request_id);
      return null;
    }

    return data.data;
  } catch (error) {
    console.error("Network error:", error);
    throw error;
  }
}
```

### Python Example

```python
import requests
import time
import os

def create_boleto(boleto_data):
    url = "https://api.monetarie_npc.com.br/api/v1/central/boletos"
    headers = {
        "X-API-Key": os.environ["MONETARIE_NPC_API_KEY"],
        "Content-Type": "application/json"
    }

    try:
        response = requests.post(
            url,
            headers=headers,
            json={"boleto": boleto_data}
        )
        data = response.json()

        if not response.ok:
            error = data.get("error", {})
            error_code = error.get("code")
            request_id = data.get("meta", {}).get("request_id")

            # Handle specific errors
            if error_code == "VALIDATION_ERROR":
                print(f"Invalid data: {error.get('details')}")
                # Show validation errors to user

            elif error_code == "DUPLICATE_BOLETO":
                print(f"Boleto already exists: {error.get('message')}")
                # Fetch existing boleto

            elif error_code == "RATE_LIMITED":
                retry_after = int(response.headers.get("Retry-After", 60))
                print(f"Rate limited. Waiting {retry_after} seconds...")
                time.sleep(retry_after)
                # Try again
                return create_boleto(boleto_data)

            elif error_code in ["PCR_UNAVAILABLE", "INTERNAL_ERROR"]:
                print(f"Server error: {error.get('message')}")
                # Schedule retry

            # Log request_id for support
            print(f"Request ID: {request_id}")
            return None

        return data.get("data")

    except requests.exceptions.RequestException as e:
        print(f"Network error: {e}")
        raise
```

---

## Contacting Support

When contacting support, always include:

1. **Request ID** - The `request_id` returned in the error response
2. **Timestamp** - Approximate date and time of the error
3. **Endpoint** - URL and HTTP method used
4. **Payload** - Request body (remove sensitive data)
5. **Response** - Complete error response received

::: info Support Channels
- **Email:** suporte@fluxiq.com.br
- **Portal:** [npcadmin-dev.fluxiq.com.br/suporte](https://npcadmin-dev.fluxiq.com.br/suporte)
- **SLA:** Responses within 4 business hours for production environment
:::

## Next Steps

- [Rate Limits](/en/reference/rate-limits) - Request limits per endpoint
- [Authentication](/en/authentication) - Configure API Key correctly
- [Environments](/en/environments) - Use sandbox for testing
