Skip to content
Last updated

Error Handling

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.

Error Response Format

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"
}

Core Fields

FieldTypeDescription
typestring (URI)URI that identifies the error type. Resolves to the documentation.
titlestringShort summary of the problem type. Consistent across all occurrences.
statusintegerHTTP status code for this occurrence.
detailstringHuman-readable explanation specific to this occurrence.
instancestring (URI)URI that identifies this specific occurrence (usually the request path).

Extension Fields

FieldTypeDescription
codestringMachine-readable sub-type (e.g., missing_required_field, invalid_cpf)
paramstringThe request parameter that caused the error
errorsarrayList of individual per-field errors (for validation failures)

Tip: Use the code field for programmatic error handling. The type identifies the broad category, while the code pinpoints the specific problem.

Field Validation Errors

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:

FieldDescription
paramThe field name that failed validation
detailHuman-readable explanation of the validation failure
codeMachine-readable validation error code

Error Type Reference

StatusTypeTitleWhen
400invalid-requestInvalid RequestMalformed syntax, missing content type, or invalid parameters
401authentication-failedAuthentication FailedMissing or invalid credentials or token
403forbiddenForbiddenValid token but insufficient permissions
404not-foundNot FoundResource does not exist or is not accessible for this partner
409conflictConflictResource already exists or action conflicts with current state
422validation-failedValidation FailedRequest parsed successfully but field values are invalid
429rate-limit-exceededRate Limit ExceededToo many requests. Check the Retry-After header.
500internalInternal ErrorUnexpected server error

All type URIs are prefixed with https://api.dinie.com.br. Click the type to see common causes, examples, and resolution.

SDK Error Handling

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");
  }
}

Rate Limiting

All responses include rate limit headers:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 97
X-RateLimit-Reset: 1709478060

When rate limited (429), the Retry-After header indicates how many seconds to wait:

Retry-After: 30

Retry Strategy

Not all errors should be retried. Use this table to decide:

StatusRetry?Strategy
400NoFix the request. The payload is malformed.
401OnceRenew the access token and resend.
403NoCheck permissions with your account manager.
404NoThe resource does not exist.
409NoResolve the conflict (e.g., duplicate resource).
422NoFix the invalid field values.
429YesWait for the time indicated in Retry-After and resend.
500YesRetry with exponential backoff.

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 429 and 500 responses. You can configure the maximum number of retries when initializing the client.