Your Own Details on the Invoice
Every invoice needs a seller โ your own company. On several paths you do not have to supply it: leave the seller out of a CSV row or a JSON invoice and GoRoute fills it in from your organisation's saved company details.
That is convenient right up to the moment an invoice goes out with the wrong company name, an old address or no VAT number, and you need to know where that came from. This page answers that. It is the seller-side counterpart of Saved Parties, which is your address book of everybody else.
All paths below are relative to https://app.goroute.ai/peppol-api.
| Method | Path | Purpose |
|---|---|---|
GET | /api/v1/invoices/default-seller | The resolved seller โ what would actually be put on an invoice right now. |
GET | /api/v1/settings/company/seller | The stored seller block, as saved in your company settings. |
PUT | /api/v1/settings/company/seller | Change the stored seller block. Partial updates. |
Where your details come fromโ
There are two sources, and they are tried in order.
- Your company settings โ the seller block you can read and write with the two
/api/v1/settings/company/sellercalls below. This wins whenever it is usable. - Your organisation record โ the name, participant identifier, VAT number and address captured when the organisation was set up. This is the floor, not an override: it is used only when company settings cannot produce a seller.
Company settings only count as usable when the seller block has both parts of its Peppol
identifier filled in: peppol_id.scheme and peppol_id.value. If either is blank, the whole
settings block is skipped and the organisation record is used instead. That is the single
most common reason a name you typed into settings does not appear on an invoice.
What would go on an invoice right nowโ
GET /api/v1/invoices/default-seller
Needs the invoices:read permission. It returns the resolved result โ settings or the
organisation record, whichever won โ as the seller object of an invoice:
{
"seller": {
"peppol_id": "0248:OM1100012345",
"name": "Muscat Trading LLC",
"registration_number": "1234567",
"vat_number": "OM1100012345",
"tax_scheme": "VAT",
"email": "billing@muscat-trading.example",
"phone": "+968 2400 0000",
"address": {
"street": "Al Khuwair Street 12",
"city": "Muscat",
"postal_code": "112",
"country": "OM"
}
}
}
seller is null when neither source can produce one โ an organisation with no profile yet.
Fields that have no value are left out of the object rather than returned as null.
This is the call to make when an invoice came out wrong. It is the same default a CSV import uses, so what you see here is what the import will use.
The stored seller block has a bank_account and a legal_name. Neither is carried into the
resolved seller object: legal_name is used only as a stand-in when name is empty, and
bank details belong to the payment part of an invoice, not to the seller party. Do not expect
them back from this call.
Reading the stored blockโ
GET /api/v1/settings/company/seller
An ordinary API key is enough; no extra permission is required. It returns the seller block exactly as stored, with any field you have never set present and empty, so the shape is always the same:
{
"peppol_id": {"scheme": "0248", "value": "OM1100012345"},
"name": "Muscat Trading LLC",
"legal_name": "Muscat Trading Limited Liability Company",
"registration_number": "1234567",
"vat_number": "OM1100012345",
"address": {
"street": "Al Khuwair Street 12",
"additional_street": "",
"city": "Muscat",
"postal_code": "112",
"country_subdivision": "",
"country_code": "OM"
},
"contact": {
"name": "Accounts Receivable",
"telephone": "+968 2400 0000",
"email": "billing@muscat-trading.example"
},
"bank_account": {
"bank_name": "Bank Muscat",
"account_number": "OM12 0001 0000 0000 0000 1234",
"bic": "BMUSOMRX"
}
}
| Field | Notes |
|---|---|
peppol_id.scheme, peppol_id.value | Both must be set for this block to be used at all. The scheme defaults to 0088 until you change it. |
name | The name that goes on the invoice. |
legal_name | Used only if name is empty. |
registration_number | Company registration number. |
vat_number | VAT or tax identifier. |
address | street, additional_street, city, postal_code, country_subdivision, country_code. A settings address is only used when city is filled in. |
contact | name, telephone, email. |
bank_account | bank_name, account_number (the IBAN), bic. |
Note that this call shows what is stored, not what would be used. If your peppol_id is
half-filled, this call still shows you the name you typed while
GET /api/v1/invoices/default-seller quietly returns the organisation record instead. When
the two disagree, the resolved call is the one telling the truth about your invoices.
Changing the stored blockโ
PUT /api/v1/settings/company/seller
Needs the settings:manage permission โ an API key without it gets 403 with
error_code: INSUFFICIENT_PERMISSION.
The body is a partial update. Send only what you want to change; everything you leave out keeps its current value, and this applies inside the nested objects too, so you can change one line of the address without restating the rest:
import requests
response = requests.put(
"https://app.goroute.ai/peppol-api/api/v1/settings/company/seller",
headers={"X-API-Key": "your_api_key", "Content-Type": "application/json"},
json={
"name": "Muscat Trading LLC",
"address": {"city": "Muscat", "country_code": "OM"},
},
timeout=30,
)
print(response.json()["name"])
The reply is the stored seller block after the change, in the same shape as the GET above.
Accepted keys are exactly the ones in the table above: peppol_id, name, legal_name,
registration_number, vat_number, address, contact and bank_account. Anything else in
the body is ignored.
Writing peppol_id here changes the identifier used when building an invoice. It does not
register anything on the Peppol network, and it does not change your organisation's own
regulated identity โ the participant identifier, VAT number and country on the organisation
record are set by GoRoute after registration and cannot be changed through the client API. If
invoices are going out under the wrong identifier, talk to support rather than working around
it here.
Reading and writing all your company settings in one callโ
The seller block is one of three blocks GoRoute keeps for your organisation. The other two are your invoice defaults (currency, payment terms, tax rate) and your branding (logo, colour, footer). There is one pair of calls that reads and writes all three together:
| Method and path | Purpose | Permission |
|---|---|---|
GET /api/v1/settings/company | Read all three blocks at once | A valid credential for the organisation; no named permission |
PATCH /api/v1/settings/company | Change any of the three blocks | settings:manage |
Use these when you want to see or set everything at once โ checking a new organisation is fully configured, for example, or copying a configuration between organisations. Use the per-block calls above when you only care about the seller.
The GET reply always has exactly three top-level keys:
{
"seller": { "peppol_id": {"scheme": "0088", "value": ""}, "name": "", "...": "..." },
"invoice_defaults": {
"currency": "EUR",
"payment_terms_days": 30,
"payment_means_code": "30",
"note": "",
"tax_rate": "25.00",
"tax_category": "S"
},
"branding": { "logo_url": "", "primary_color": "#0066CC", "footer_text": "" }
}
Nothing is ever missing from that reply. If you have never stored a setting, you get the shipped starting values โ empty strings throughout the seller block, and the invoice and branding values shown above. An empty string means "not set", not "set to nothing".
The write merges; it does not replaceโ
PATCH is a deep merge onto what you already have. Send one field inside seller.address
and every other field, in that address and in the other two blocks, keeps its current value.
There is no way to clear a block by omitting it:
import requests
response = requests.patch(
"https://app.goroute.ai/peppol-api/api/v1/settings/company",
headers={"X-API-Key": "your_api_key", "Content-Type": "application/json"},
json={
"seller": {"name": "Muscat Trading LLC"},
"invoice_defaults": {"currency": "OMR", "tax_rate": "5.00"},
},
timeout=30,
)
settings = response.json()
print(settings["invoice_defaults"]["currency"])
The reply is all three blocks after the change, in the same shape as the GET. A body
containing none of seller, invoice_defaults or branding changes nothing and simply
returns your current settings.
configA connector's config is replaced wholesale on every write, so you must read it, edit the
object you got back and send the whole thing. Company settings are the other way round: send
only what you are changing. Do not carry a habit from one page to the other โ see
Connector API.
invoice_defaults block is stored, not appliedcurrency: "EUR", tax_rate: "25.00" and tax_category: "S" are what an organisation starts
with if nobody sets them, and they are not derived from your country. That is worth knowing if
you read this block and act on it โ but changing it changes no invoice by itself. Nothing in
GoRoute reads invoice_defaults when it creates, validates, prefills or sends an invoice; the
auto-fix that supplies a missing currency writes a fixed EUR of its own and never looks at what
you stored. See
Organisation invoice defaults โ stored, but never applied.
If you want values the product really does put on an invoice, use an
invoice template.
The seller block is the exception, and it is why this page exists: that one is read when an
invoice is built for you. For the codes Oman requires on an invoice, read the
Oman country guide โ this page does not restate tax rules.
Your logo, colour and footerโ
The branding block โ the third of the three โ has its own pair of calls, and the logo has two more,
because an image cannot travel in a JSON field. All four are tagged Settings in the API reference
and take the same credential as everything else on this page.
| Method and path | Purpose | Permission |
|---|---|---|
GET /api/v1/settings/company/branding | Read the branding block | A valid credential for the organisation; no named permission |
PUT /api/v1/settings/company/branding | Change logo_url, primary_color or footer_text | settings:manage |
POST /api/v1/settings/company/logo | Upload the logo image itself | settings:manage or branding:manage โ either is enough |
GET /api/v1/settings/company/logo | Fetch the logo image back | A valid credential for the organisation; no named permission |
The three stored fields start as logo_url: "", primary_color: "#0066CC" and footer_text: "",
the same values the all-in-one GET /api/v1/settings/company shows. The read may also return
logo_s3_key, the private-storage key of an uploaded logo; it is set by the upload below and is not
something you write yourself.
The PUT changes only what you sendโ
This one behaves like PATCH despite being a PUT: fields you leave out keep their current values.
import requests
response = requests.put(
"https://app.goroute.ai/peppol-api/api/v1/settings/company/branding",
headers={"X-API-Key": "your_api_key", "Content-Type": "application/json"},
json={"primary_color": "#123456"},
timeout=30,
)
print(response.json()["primary_color"])
That call leaves logo_url and footer_text exactly as they were. The three keys above are the only
ones accepted; anything else in the body is ignored. To empty a field, send it as an empty string โ
sending null is treated as "not mentioned" and changes nothing.
Uploading a logoโ
POST /api/v1/settings/company/logo
Send the image as multipart/form-data in a field named file. PNG, JPEG, SVG and WebP only, and
at most 2 MB. Anything else is refused with 400 โ "Unsupported file type: โฆ. Use PNG, JPEG, SVG,
or WebP." or "Logo must be under 2 MB." The reply gives you logo_url, the filename you sent and
the size in bytes, and the upload writes logo_url into the branding block for you, so there is no
second call to make.
Upload the image rather than pointing logo_url at a picture of your own: the renderer reads the
uploaded file straight from storage, and that is the path that is certain to work.
logo_url is not a public addressIt reads /peppol-api/api/v1/settings/company/logo, and that path needs a credential โ the logo is
kept in private, encrypted storage rather than on a public URL. Put it in a public web page, an email
template or a document you send to a customer and they will see a broken image; the dashboard works
because it fetches the image with your session and displays what came back. GET that path with no
logo uploaded and you get 404 "No logo uploaded".
The uploaded logo, primary_color and footer_text do reach the PDFs GoRoute renders for the
documents you send โ the logo is embedded in the file rather than linked, which is why the private
address above is not a problem for it. An invoice that carries its own seller logo in
metadata.seller_branding.logo_url uses that instead, and on a document you received your own
logo never replaces the sender's in the header.
Checklist when an invoice has the wrong seller on itโ
- Call
GET /api/v1/invoices/default-seller. This is what is really being used. - If it is not what you expected, call
GET /api/v1/settings/company/sellerand checkpeppol_id.schemeandpeppol_id.valueare both filled in. If either is blank, your settings are being skipped entirely. - Check
address.city. A settings address with no city is dropped, and the invoice comes out without a seller address. - Fix it with
PUT /api/v1/settings/company/seller, then calldefault-selleragain to confirm the resolved result changed.
Relatedโ
- CSV Import โ the columns that let you override these defaults per row
- Saved Parties โ the same idea for your customers
- Send an Invoice