Error handling
Every failed call raises a typed exception. The class tells you the
category; each instance carries the HTTP statusCode, a message, and the
raw response body (rawBody) for logging. Catch the specific type you can
recover from, and fall back to the base type for everything else.
Exception hierarchy
The semantics are identical across languages; only the names differ. Node
uses *Error, Java and .NET use *Exception, and Swift collapses them into
a single LinaAPIError with a kind enum.
| HTTP | Meaning | Node | Java / .NET | Swift kind |
|---|---|---|---|---|
| — | Base type (all failures) | LinaApiError | LinaApiException | — |
| 400 | Invalid input / validation | BadRequestError | BadRequestException | .badRequest |
| 401 | Missing or invalid token | UnauthorizedError | UnauthorizedException | .unauthorized |
| 403 | Role/tenant not allowed | ForbiddenError | ForbiddenException | .forbidden |
| 404 | Resource not found | NotFoundError | NotFoundException | .notFound |
| 422 / 424 | Account holder (RP) failure | DependencyError | DependencyException | .dependency |
| 429 | Rate limit exceeded | RateLimitError | RateLimitException | .rateLimited |
| 5xx | Unexpected backend error | ServerError | ServerException | .server |
| — | Timeout / connection failure | NetworkError | NetworkException | .network |
Catching errors
import {
LinaApiError, DependencyError, UnauthorizedError, RateLimitError,
} from '@linainfratech/embedded-payments';
try {
await client.payments.processJsr(req, { clientIp });
} catch (e) {
if (e instanceof DependencyError) {
// 424 — account holder failed; ask the payer to try again later
} else if (e instanceof RateLimitError) {
// 429 — back off; e.retryAfterMs (if present) tells you how long
} else if (e instanceof UnauthorizedError) {
// 401 — check client credentials / roles
} else if (e instanceof LinaApiError) {
// e.rawBody may contain the payer's CPF and creditor account details —
// treat it as PII: don't log/persist it as-is (mask or redact first).
console.error(e.statusCode, e.message);
} else {
throw e; // not from the SDK
}
}try {
client.payments.processJsr(req, CallOptions.clientIp(ip));
} catch (DependencyException e) { // 424 — account holder failed
} catch (RateLimitException e) { // 429 — e.retryAfterMs() tells you how long
} catch (UnauthorizedException e) { // 401 — credentials / roles
} catch (LinaApiException e) { // base
// e.rawBody() may contain the payer's CPF and creditor account details —
// treat it as PII: don't log/persist it as-is.
System.err.println(e.statusCode() + " " + e.getMessage());
}do {
_ = try await client.payments.processJsr(req, options: .clientIp(ip))
} catch let error as LinaAPIError {
switch error.kind {
case .dependency: break // 424 — account holder failed
case .rateLimited: break // 429 — back off (Retry-After honored on idempotent calls)
case .unauthorized: break // 401 — credentials / roles
default:
// error.rawBody may contain the payer's CPF and creditor account details —
// treat it as PII: don't log/persist it as-is.
print(error.statusCode ?? -1, error.message)
}
}try
{
await client.Payments.ProcessJsrAsync(req, CallOptions.WithClientIp(ip));
}
catch (DependencyException) { /* 424 — account holder failed */ }
catch (RateLimitException e) { /* 429 — e.RetryAfterMs tells you how long */ }
catch (UnauthorizedException) { /* 401 — credentials / roles */ }
catch (LinaApiException e)
{
// e.RawBody may contain the payer's CPF and creditor account details —
// treat it as PII: don't log/persist it as-is.
Console.Error.WriteLine($"{e.StatusCode} {e.Message}");
}Client-side validation
Two calls validate their input before hitting the network and raise a
BadRequestError (or the language equivalent) immediately:
pix.getDetailsrequires exactly one ofpixKeyorqrCode. Passing both or neither fails locally.consents.createJsrrequires exactly one ofpayment(inline) orpaymentId(reference).
Retries and timeouts
The client retries automatically, but only on idempotent calls (GET
requests and token fetches) and only on NetworkError, RateLimitError
(429, honoring Retry-After), or 5xx responses, using backoff. Non-idempotent
calls — createJsr, processJsr, and other POST/PATCH methods — are never
retried automatically, so a NetworkError there does not guarantee the
request did not reach the backend.
| Option | Default | Effect |
|---|---|---|
timeout | 30000 ms | Per-request deadline; a breach raises NetworkError. |
maxRetries | 2 | Extra attempts on idempotent calls only. |
Next steps
- Link an account — the enrollment flow.
- Pay a QR Code — the payment flow these errors surface in.
- SDK overview — the full method and service map.