The one error type of the SDK.
Every function returns {:error, %Unicom360.Error{}} on failure, and its ! variant raises
the same struct. type says what went wrong; class/1 names the canonical error class the
other Unicom360 SDKs use, which also tells the business refusals apart.
type | class/1 | When |
|---|---|---|
:configuration_error | ConfigurationError | no API key, an unusable option, a blank webhook secret |
:connection_error | APIConnectionError | no complete response (refused, DNS, reset) |
:timeout_error | APITimeoutError | the connection or the response timed out |
:api_status_error | APIStatusError | any other non-2xx (3xx, 403, 404...), or a 2xx that is not an envelope |
:authentication_error | AuthenticationError | HTTP 401 |
:rate_limit_error | RateLimitError | HTTP 429; retry_after is set |
:invalid_request_error | InvalidRequestError | HTTP 400: the request's shape is wrong |
:api_server_error | APIServerError | HTTP 5xx |
:api_error | APIError, InsufficientBundleError, DuplicateReferenceError, NoValidRecipientsError, SessionWindowClosedError | HTTP 200 with success: false (or status: false): a business refusal |
:signature_verification_error | SignatureVerificationError | a webhook failed verification; reason says which check |
:unicom360_error | Unicom360Error | a webhook or callback body that is not a JSON object |
HTTP 200 is not success: a refusal such as an unknown sender ID arrives as HTTP 200 with
success: false, and is an :api_error whose code says why (see Unicom360.Codes).
Fields:
message: human-readable text; for API errors, the gateway's message (an array of messages is joined with"; "). Never contains the API key.code: the normalised code (Unicom360.Codes.normalize/1) on API errors, elsenil.http_status,api_reference(quote it to support),raw_body,headers(the response's, names lower-cased) anddata(the envelope'sdata, raw) on API errors.attempts: the HTTP attempts an operation made, retries included.retry_after: on a:rate_limit_error, milliseconds until the next UTC minute, when the gateway's per-minute window resets.original_message_id: on aDuplicateReferenceError, themessage_idthe earlier send returned, when the gateway says (session sends).results: on aNoValidRecipientsError, why each recipient was rejected.reason: on a:signature_verification_error, one of:missing_signature,:missing_timestamp,:invalid_timestamp,:malformed_signature,:timestamp_out_of_tolerance,:signature_mismatch.cause: on a:connection_erroror:timeout_error, the underlying exception.
A DuplicateReferenceError with attempts greater than 1 means an earlier attempt of the
same call very probably succeeded: the retry was refused because that attempt had already
used the reference. Treat the message as sent.
Summary
Functions
The canonical class name of an error, as the other Unicom360 SDKs name it.
Whether the error is a :connection_error or a :timeout_error (a timeout is a connection
error too, as APITimeoutError extends APIConnectionError).
Whether the error came from a non-2xx response, or a 2xx that was not an envelope
(APIStatusError and its subclasses).
Types
@type reason() ::
:missing_signature
| :missing_timestamp
| :invalid_timestamp
| :malformed_signature
| :timestamp_out_of_tolerance
| :signature_mismatch
@type t() :: %Unicom360.Error{ __exception__: true, api_reference: String.t() | nil, attempts: pos_integer() | nil, cause: Exception.t() | nil, code: String.t() | nil, data: term(), headers: %{optional(String.t()) => [String.t()]} | nil, http_status: non_neg_integer() | nil, message: String.t(), original_message_id: String.t() | nil, raw_body: String.t() | nil, reason: reason() | nil, results: [Unicom360.WhatsApp.TemplateResult.t()] | nil, retry_after: non_neg_integer() | nil, type: type() }
@type type() ::
:unicom360_error
| :configuration_error
| :connection_error
| :timeout_error
| :api_status_error
| :authentication_error
| :rate_limit_error
| :invalid_request_error
| :api_server_error
| :api_error
| :signature_verification_error
Functions
The canonical class name of an error, as the other Unicom360 SDKs name it.
An :api_error is classed by its code: INSUFFICIENT_BUNDLE is "InsufficientBundleError",
DUPLICATE_REFERENCE "DuplicateReferenceError", NO_VALID_RECIPIENTS
"NoValidRecipientsError", SESSION_WINDOW_CLOSED "SessionWindowClosedError", anything else
"APIError".
iex> Unicom360.Error.class(%Unicom360.Error{type: :api_error, code: "INSUFFICIENT_BUNDLE"})
"InsufficientBundleError"
iex> Unicom360.Error.class(%Unicom360.Error{type: :rate_limit_error})
"RateLimitError"
Whether the error is a :connection_error or a :timeout_error (a timeout is a connection
error too, as APITimeoutError extends APIConnectionError).
Whether the error came from a non-2xx response, or a 2xx that was not an envelope
(APIStatusError and its subclasses).