Skip to main content

Sending Invoice Email from Your Own Domain

By default every invoice email GoRoute sends leaves from a GoRoute address. If you would rather your buyers saw your own domain in the From line, you register that domain, publish a short list of DNS records, and wait for verification. Five API calls cover the whole feature.

All paths below are relative to https://app.goroute.ai/peppol-api. Every call is scoped to the organisation of the credential you send.

This changes two emails, and only two

A verified sending domain changes the From address of the draft invoice email:

  • POST /api/v1/drafts/{draft_id}/send-via-goroute โ€” the first send of a draft
  • POST /api/v1/drafts/{draft_id}/resend โ€” any later send of the same draft

It does not change these, which always send from GoRoute's own verified sender, whether or not you have a domain of your own:

  • POST /api/v1/transactions/{transaction_id}/email โ€” emailing a transaction's document
  • POST /api/v1/documents/{document_id}/email โ€” emailing a pro forma invoice or delivery note

On those two calls sender_name sets the display name only. The From address stays GoRoute's, exactly as Delivery and Formats says.

The five callsโ€‹

CallWhat it does
GET /api/v1/sender-domainsLists the domains your organisation has registered, newest first
POST /api/v1/sender-domainsRegisters a domain and asks for its DKIM records
GET /api/v1/sender-domains/{domain_id}Reads one domain, including the DNS records to publish
POST /api/v1/sender-domains/{domain_id}/verifyRe-checks verification now instead of waiting for the next automatic check
DELETE /api/v1/sender-domains/{domain_id}Removes the domain

Authentication. All five accept either an organisation API key in the X-API-Key header or a signed-in portal session. None of them requires a particular permission, so any valid API key for your organisation can register, verify and delete a sending domain. Treat that as it is: there is no separate "manage sending domains" right to withhold.

Step 1 โ€” register the domainโ€‹

POST /api/v1/sender-domains
X-API-Key: your-api-key
Content-Type: application/json

{
"domain": "acme.example",
"from_address": "billing@acme.example",
"reply_to_address": "accounts@acme.example"
}

domain is required and is stored lower-case with any trailing dot removed. Anything that is not a valid domain name is refused with 400. from_address and reply_to_address are optional; both are addresses, up to 320 characters.

The answer is 201 with the domain's current state and the DNS records you have to publish:

{
"id": "4f0f2a76-5a3c-4e3a-9a1b-22c0f1d7e3b4",
"domain": "acme.example",
"status": "pending",
"dkim_status": "pending",
"spf_status": null,
"dmarc_status": null,
"dkim_tokens": [
"hs4mkvbn7q2xz6rt3ldjw9cyp5gu8af1",
"t9wbq3nd7v2hm5kzx8plr4jc6sy1gaef",
"z2cpx7fk4nmr9td6wsvh3ylb8qja5geu"
],
"from_address": "billing@acme.example",
"reply_to_address": "accounts@acme.example",
"verified_at": null,
"last_checked_at": "2026-09-14T09:12:44.118000+00:00",
"dns_records": {
"dkim": [
{
"type": "CNAME",
"name": "hs4mkvbn7q2xz6rt3ldjw9cyp5gu8af1._domainkey.acme.example",
"value": "hs4mkvbn7q2xz6rt3ldjw9cyp5gu8af1.dkim.amazonses.com"
}
],
"spf": {
"type": "TXT",
"name": "acme.example",
"value": "v=spf1 include:amazonses.com ~all"
},
"dmarc": {
"type": "TXT",
"name": "_dmarc.acme.example",
"value": "v=DMARC1; p=none; rua=mailto:dmarc-reports@acme.example"
},
"verification": null
},
"is_verified": false
}

The dkim list is shortened above: there is one CNAME for every entry in dkim_tokens.

Registering the same domain twice is safe. If your organisation already has a row for that domain, the call updates it and re-fetches the DKIM records rather than creating a second one. Note that sending from_address or reply_to_address again replaces the stored value, but sending them as null does not clear an address you set earlier.

If the mail provider cannot be reached when you register, the domain is stored as pending with no DKIM records issued yet โ€” dkim_tokens is empty and the dkim list in dns_records is empty with it. Call the domain again later; the records appear once they have been issued.

Step 2 โ€” publish the DNS recordsโ€‹

Publish everything in dns_records at the registrar or DNS host for the domain.

RecordNamePurpose
CNAME, one per DKIM token<token>._domainkey.<your-domain>Lets the mail be signed as yours. This is the one verification waits for
TXT<your-domain>SPF โ€” names the sending service as allowed to send for you
TXT_dmarc.<your-domain>DMARC โ€” a monitoring-only policy (p=none) with a reports address on your own domain
TXT_amazonses.<your-domain>Only present when a verification token has been issued. It is null in dns_records until then

Two honest notes about these:

  • The SPF and DMARC values are suggestions, not our checks. If your domain already publishes SPF or DMARC, merge rather than replace โ€” a second SPF record on the same name breaks both. The DMARC value we hand back monitors only; it enforces nothing, and it points reports at dmarc-reports@<your-domain>, an address you have to be able to receive at if you want them.
  • spf_status and dmarc_status are always null. They are in the response, but nothing in the service ever fills them in. Do not read them as "we checked your SPF" โ€” we do not check it. Verification depends on DKIM alone.

Step 3 โ€” wait for verification, or ask for it nowโ€‹

GoRoute re-checks every domain that is pending or temporary_failure every ten minutes, and re-checks an already verified domain about once a day. DNS changes are usually picked up within the hour, but that is your DNS host's timing, not ours.

To check immediately rather than wait for the next round:

POST /api/v1/sender-domains/{domain_id}/verify
X-API-Key: your-api-key

This re-reads the domain's status from the mail provider and returns the same shape as GET /api/v1/sender-domains/{domain_id}. It does not query your DNS itself, so a record you published seconds ago may still show as pending.

status is one of:

statusMeaning
pendingRegistered; DKIM not verified yet. This is also where a domain sits when the provider could not be asked
verifiedVerified. verified_at is set, is_verified is true, and draft emails can now go out from this domain
failedVerification failed. Check the DKIM CNAMEs are published exactly as given
temporary_failureA transient failure at the provider. It stays in the ten-minute re-check loop

dkim_status is the provider's own DKIM state in lower case โ€” pending while it waits, success once the signature verifies. last_checked_at is the last time we asked, and it moves even when nothing changed.

What changes once a domain is verifiedโ€‹

Draft invoice emails go out from your domain:

  • The From address is your from_address if you set one. If you did not, the mail is sent from invoices@<your-domain>.
  • The name the buyer sees is your from_address if you set one, and the bare domain โ€” acme.example โ€” if you did not. These are deliberately two different things, so a buyer never sees a synthesised invoices@ address presented as your name.
  • Replies go to reply_to_address when you set one.

Until a domain is verified, POST /api/v1/drafts/{draft_id}/send-via-goroute and POST /api/v1/drafts/{draft_id}/resend are refused with 412 and the message "No verified sender domain for this organization." That refusal is about the domain only; a draft send can still fail for other reasons โ€” 400 with no buyer address, 409 when a first send has already happened, 429 after three resends of the same draft in 24 hours, and 503 when email is not switched on in that environment.

If you have more than one verified domain, only one of them is used, and there is no setting that chooses which. Register the single domain you want to send from.

Removing a domainโ€‹

DELETE /api/v1/sender-domains/{domain_id}
X-API-Key: your-api-key

204, and the domain is gone. Read that literally before you call it:

  • There is no confirmation step and no undo. The record is deleted outright, not archived.
  • Any valid API key for your organisation can do it, with no special permission.
  • From that moment, every draft invoice email for your organisation is refused with 412 until you register the domain again and it verifies โ€” which waits on DNS and on the ten-minute check, so it is not a matter of seconds.

An unknown id, or one belonging to another organisation, answers 404 on this call and on every other call that takes a domain_id.

What this page does not tell youโ€‹

  • Whether email is switched on in the environment you are calling. Draft sends answer 503 when it is not. That is configuration, not something these five calls report.
  • Anything about GoRoute's own sending domain. The address transaction and non-fiscal document emails come from is ours and is not configurable through this API.