Skip to main content
The official PHP client for the Nateq API. Framework-agnostic core, with an auto-discovered Laravel service provider and facade. Zero required runtime dependencies, so it won’t fight your app over a Guzzle version.

Packagist

nateq/sdk

GitHub

Source and issues

Requirements

  • PHP 8.2 or newer
  • ext-curl and ext-json
  • Laravel 11 or 12 (optional — the SDK works without it)

Install

In Laravel, the service provider and Nateq facade are auto-discovered. There’s nothing to register.

Quickstart

Create an API key with the emails:send scope, then put it in your environment:
In Laravel, resolve the client instead of constructing it:

Authentication

The SDK reads NATEQ_API_KEY by default. Pass it explicitly to load it from a secret manager, or to talk to more than one organization:
The key is validated locally before any request, so a mistyped key fails immediately rather than going out over the network.
var_dump(), json_encode(), and framework error pages all redact the key, and serializing a client throws on purpose. But print_r() and var_export() have no redaction hook in PHP and will print it — don’t pass the client to either.

Sending email

send() returns once the API accepts the message. Delivery happens afterwards — a successful return means Nateq took responsibility for it, not that it landed.
Provide htmlBody, plainTextBody, or both. Omit fromEmail and emailAddressId to use your organization’s default verified address.

Reading email

EmailStatus is an enum with helpers, so you don’t have to memorise which of the nine statuses count as success:
List sends, newest first. The result is countable and iterable:
limit defaults to 50 and is capped at 100.
The API returns more fields than the SDK models. Anything not promoted to a property is still on $email->raw, so a new field works without an SDK upgrade.

Errors

Everything extends NateqException, so one catch covers the surface:
See Errors for the underlying API codes.

Retries and duplicate sends

Reads (get, list) retry automatically on timeouts, 5xx, and connection failures, with exponential backoff that honours Retry-After. send() does not. The API has no idempotency key, so a send that fails after reaching the server may already have gone out. Replaying it could mail your customer twice, and the SDK won’t make that call for you. The exception is a 429, which the API raises before anything is sent — so it is retried, because a duplicate is impossible. If a send() throws TimeoutException or ServerException, the outcome is genuinely unknown. Look it up before retrying:

Laravel

Publish the config only if you want to edit it:
Inject the client, or use the facade:

Send from a queued job

Email is a network call to a third party. Doing it inline ties your response time to ours.
Resolve the client through handle(), as above — never store it on the job as a property. Job properties are serialized into the queue payload, and the client refuses to serialize precisely so your API key can’t end up sitting in Redis in plain text.
If you change NATEQ_API_KEY and nothing happens, you have a cached config:

Testing

Don’t hit the API from your test suite. Implement HttpClient with a fake:
In Laravel, bind it and the container-resolved client picks it up — facade included:
The same seam routes traffic through your own stack — Guzzle, Symfony HttpClient, or an outbound proxy.