The Dinie API uses the RFC 9457 Problem Details format for all error responses. Every error has a consistent structure, a machine-readable type URI, and a human-readable description.
All errors are returned with content type application/problem+json:
{
"type": "https://api.dinie.com.br/errors/invalid-request",
"title": "Invalid Request",
"status": 400,
"detail": "The 'cpf' field is required.",
"instance": "/v3/customers"
}| Field | Type | Description |
|---|---|---|
type | string (URI) | URI that identifies the error type. Resolves to the documentation. |
title | string | Short summary of the problem type. Consistent across all occurrences. |
status | integer | HTTP status code for this occurrence. |
detail | string | Human-readable explanation specific to this occurrence. |
instance | string (URI) | URI that identifies this specific occurrence (usually the request path). |
| Field | Type | Description |
|---|---|---|
code | string | Machine-readable sub-type (e.g., missing_required_field, invalid_cpf) |
param | string | The request parameter that caused the error |
errors | array | List of individual per-field errors (for validation failures) |
Tip: Use the
codefield for programmatic error handling. Thetypeidentifies the broad category, while thecodepinpoints the specific problem.
When a request has correct syntax but invalid field values, the response includes an errors array with details for each invalid field:
{
"type": "https://api.dinie.com.br/errors/validation-failed",
"title": "Validation Failed",
"status": 422,
"detail": "One or more fields failed validation.",
"errors": [
{
"param": "email",
"detail": "Must be a valid email address.",
"code": "invalid_format"
},
{
"param": "cpf",
"detail": "CPF is already registered.",
"code": "already_exists"
}
]
}Each item in the errors array contains:
| Field | Description |
|---|---|
param | The field name that failed validation |
detail | Human-readable explanation of the validation failure |
code | Machine-readable validation error code |
| Status | Type | Title | When |
|---|---|---|---|
| 400 | invalid-request | Invalid Request | Malformed syntax, missing content type, or invalid parameters |
| 401 | authentication-failed | Authentication Failed | Missing or invalid credentials or token |
| 403 | forbidden | Forbidden | Valid token but insufficient permissions |
| 404 | not-found | Not Found | Resource does not exist or is not accessible for this partner |
| 409 | conflict | Conflict | Resource already exists or action conflicts with current state |
| 422 | validation-failed | Validation Failed | Request parsed successfully but field values are invalid |
| 429 | rate-limit-exceeded | Rate Limit Exceeded | Too many requests. Check the Retry-After header. |
| 500 | internal | Internal Error | Unexpected server error |
All type URIs are prefixed with https://api.dinie.com.br. Click the type to see common causes, examples, and resolution.
The SDKs throw typed exceptions for each error category:
import Dinie, {
AuthenticationError,
NotFoundError,
ValidationError,
RateLimitError,
} from "dinie";
try {
const customer = await dinie.customers.create({
cpf: "invalid",
name: "Joao Silva",
email: "joao@example.com",
});
} catch (error) {
if (error instanceof ValidationError) {
console.error("Validation failed:", error.message);
for (const fieldError of error.errors) {
console.error(` ${fieldError.param}: ${fieldError.detail}`);
}
} else if (error instanceof AuthenticationError) {
console.error("Authentication failed -- check your credentials");
} else if (error instanceof RateLimitError) {
console.error(`Rate limit reached. Retry in ${error.retryAfter}s`);
} else if (error instanceof NotFoundError) {
console.error("Resource not found");
}
}All responses include rate limit headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 97
X-RateLimit-Reset: 1709478060When rate limited (429), the Retry-After header indicates how many seconds to wait:
Retry-After: 30Not all errors should be retried. Use this table to decide:
| Status | Retry? | Strategy |
|---|---|---|
| 400 | No | Fix the request. The payload is malformed. |
| 401 | Once | Renew the access token and resend. |
| 403 | No | Check permissions with your account manager. |
| 404 | No | The resource does not exist. |
| 409 | No | Resolve the conflict (e.g., duplicate resource). |
| 422 | No | Fix the invalid field values. |
| 429 | Yes | Wait for the time indicated in Retry-After and resend. |
| 500 | Yes | Retry with exponential backoff. |
For retryable errors (429, 500), use exponential backoff with jitter:
const MAX_RETRIES = 3;
async function requestWithRetry(fn: () => Promise<any>) {
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
try {
return await fn();
} catch (error) {
if (!isRetryable(error) || attempt === MAX_RETRIES) throw error;
const baseDelay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
const jitter = Math.random() * 500;
await sleep(baseDelay + jitter);
}
}
}Info: The SDKs implement automatic retries with exponential backoff for
429and500responses. You can configure the maximum number of retries when initializing the client.