Skip to main content

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.

MethodPathPurpose
GET/api/v1/invoices/default-sellerThe resolved seller โ€” what would actually be put on an invoice right now.
GET/api/v1/settings/company/sellerThe stored seller block, as saved in your company settings.
PUT/api/v1/settings/company/sellerChange the stored seller block. Partial updates.

Where your details come fromโ€‹

There are two sources, and they are tried in order.

  1. Your company settings โ€” the seller block you can read and write with the two /api/v1/settings/company/seller calls below. This wins whenever it is usable.
  2. 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.

Two things settings hold that do not reach the invoice seller

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"
}
}
FieldNotes
peppol_id.scheme, peppol_id.valueBoth must be set for this block to be used at all. The scheme defaults to 0088 until you change it.
nameThe name that goes on the invoice.
legal_nameUsed only if name is empty.
registration_numberCompany registration number.
vat_numberVAT or tax identifier.
addressstreet, additional_street, city, postal_code, country_subdivision, country_code. A settings address is only used when city is filled in.
contactname, telephone, email.
bank_accountbank_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.

Your Peppol identifier, VAT number and country are not always yours to set

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 pathPurposePermission
GET /api/v1/settings/companyRead all three blocks at onceA valid credential for the organisation; no named permission
PATCH /api/v1/settings/companyChange any of the three blockssettings: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.

This is the opposite of how the Connector API writes its config

A 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.

The invoice_defaults block is stored, not applied

currency: "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.

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 pathPurposePermission
GET /api/v1/settings/company/brandingRead the branding blockA valid credential for the organisation; no named permission
PUT /api/v1/settings/company/brandingChange logo_url, primary_color or footer_textsettings:manage
POST /api/v1/settings/company/logoUpload the logo image itselfsettings:manage or branding:manage โ€” either is enough
GET /api/v1/settings/company/logoFetch the logo image backA 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.

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 address

It 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โ€‹

  1. Call GET /api/v1/invoices/default-seller. This is what is really being used.
  2. If it is not what you expected, call GET /api/v1/settings/company/seller and check peppol_id.scheme and peppol_id.value are both filled in. If either is blank, your settings are being skipped entirely.
  3. Check address.city. A settings address with no city is dropped, and the invoice comes out without a seller address.
  4. Fix it with PUT /api/v1/settings/company/seller, then call default-seller again to confirm the resolved result changed.