Billing addresses and invoicing

Manage billing addresses, validate a VAT number, and manage invoice profiles.

Billing addresses and invoice profiles are referenced by UUID from
bookings and payment methods
— save one here first, then pass its id as billingAddressId /
invoiceProfileId elsewhere. All requests require the
consumer HMAC and a traveler bearer token.

Billing addresses

GET    /v1/billing/addresses?scope=user|account
POST   /v1/billing/addresses
PATCH  /v1/billing/addresses/{address_id}
DELETE /v1/billing/addresses/{address_id}

scope=user returns addresses owned by the traveler; scope=account returns
addresses shared across the account.

curl -X POST "$TRAVELTECH_BASE_URL/v1/billing/addresses" \
  -H "TravelTech-Consumer: $CONSUMER" \
  -H "TravelTech-Timestamp: $TIMESTAMP" \
  -H "TravelTech-Signature: $SIGNATURE" \
  -H "Authorization: Bearer $TRAVELER_JWT" \
  -H "Content-Type: application/json" \
  -d '{"type":"BUSINESS","nominee":"Acme Travel Ltd","addressLine1":"221B Baker Street","city":"London","postalCode":"NW1 6XE","countryCode":"GB","vatNumber":"GB123456789","isDefaultForType":true,"isPersonal":false}'
import httpx

from your_signing_module import sign  # see Authentication for the full algorithm

method, path = "POST", "/v1/billing/addresses"
body = (
    b'{"type":"BUSINESS","nominee":"Acme Travel Ltd",'
    b'"addressLine1":"221B Baker Street","city":"London",'
    b'"postalCode":"NW1 6XE","countryCode":"GB","vatNumber":"GB123456789",'
    b'"isDefaultForType":true,"isPersonal":false}'
)
timestamp = str(int(time.time()))

response = httpx.post(
    f"{BASE_URL}{path}",
    content=body,
    headers={
        "TravelTech-Consumer": CONSUMER,
        "TravelTech-Timestamp": timestamp,
        "TravelTech-Signature": sign(method, path, body, timestamp),
        "Authorization": f"Bearer {traveler_jwt}",
        "Content-Type": "application/json",
    },
)
const method = "POST";
const path = "/v1/billing/addresses";
const body = JSON.stringify({
  type: "BUSINESS",
  nominee: "Acme Travel Ltd",
  addressLine1: "221B Baker Street",
  city: "London",
  postalCode: "NW1 6XE",
  countryCode: "GB",
  vatNumber: "GB123456789",
  isDefaultForType: true,
  isPersonal: false,
});
const timestamp = String(Math.floor(Date.now() / 1000));

await fetch(`${BASE_URL}${path}`, {
  method,
  body,
  headers: {
    "TravelTech-Consumer": CONSUMER,
    "TravelTech-Timestamp": timestamp,
    "TravelTech-Signature": sign(method, path, body, timestamp),
    Authorization: `Bearer ${travelerJwt}`,
    "Content-Type": "application/json",
  },
});

type is BUSINESS, FREELANCE, or PRIVATE; addressLine1, city,
postalCode, and countryCode (ISO alpha-2) are required. Response
(201):

{
  "id": "018f2c1a-9b3e-7c4d-8a1f-3e5b7c9d1a2f",
  "type": "BUSINESS",
  "label": null,
  "nominee": "Acme Travel Ltd",
  "firstName": null,
  "lastName": null,
  "addressLine1": "221B Baker Street",
  "addressLine2": null,
  "city": "London",
  "region": null,
  "postalCode": "NW1 6XE",
  "countryCode": "GB",
  "vatNumber": "GB123456789",
  "vatValidationStatus": "UNVERIFIED",
  "taxCode": null,
  "pec": null,
  "sdiCode": null,
  "emailRecipients": [],
  "isDefaultForType": true
}

Deleting an address that is still a payment method's or invoice profile's
default requires a replacement — pass
transferInvoiceProfileToBillingAddressId to move the default to another
address in the same request, or the delete returns 422.

VAT validation

POST /v1/billing/vat/validate checks a VAT number's format and returns
whether it looks valid:

{ "vatNumber": "GB123456789", "countryCode": "GB" }
{ "valid": true, "companyName": null, "address": null }

POST /v1/billing/addresses/{address_id}/reverify-vat re-runs validation
against a saved address's stored vatNumber and updates its
vatValidationStatus (VERIFIED, FAILED, or UNVERIFIED). An unknown
address_id returns 404:

{
  "error": {
    "code": "RESOURCE_NOT_FOUND",
    "message": "Billing address 018f2c1a-9b3e-7c4d-8a1f-3e5b7c9d1a2f not found",
    "details": [],
    "recoveryAction": "CONTACT_SUPPORT"
  }
}

Invoice profiles

GET    /v1/invoice-profiles?scope=user|account
GET    /v1/invoice-profiles/{profile_id}
GET    /v1/invoice-profiles/{profile_id}/history
POST   /v1/invoice-profiles?scope=user|account
PATCH  /v1/invoice-profiles/{profile_id}
DELETE /v1/invoice-profiles/{profile_id}
{
  "name": "Acme Travel Ltd — EMEA",
  "vatNumber": "GB123456789",
  "billingAddressId": "018f2c1a-9b3e-7c4d-8a1f-3e5b7c9d1a2f",
  "isDefault": true,
  "emailRecipients": ["[email protected]"]
}

Response (InvoiceProfileOut):

{
  "id": "018f2c1b-1a2b-7c3d-9e4f-5a6b7c8d9e0f",
  "companyName": "Acme Travel Ltd — EMEA",
  "name": "Acme Travel Ltd — EMEA",
  "defaultBillingAddressId": "018f2c1a-9b3e-7c4d-8a1f-3e5b7c9d1a2f",
  "defaultPaymentMethod": null,
  "defaultPaymentOption": null,
  "isDefault": false,
  "isRestricted": false,
  "label": null,
  "sdiCode": null,
  "pec": null,
  "emailRecipients": ["[email protected]"],
  "vatStatus": "VERIFIED",
  "createdAt": "2026-02-10T09:00:00Z",
  "updatedAt": "2026-02-10T09:00:00Z"
}

GET /v1/invoice-profiles/{profile_id}/history returns a plain array (not the
paged items/meta envelope) of issued invoices against the profile:

[
  { "id": "018f2c1c-...", "invoiceNumber": "INV-2026-00042", "amount": "149.90", "currency": "EUR", "issuedAt": "2026-02-11T00:00:00Z", "status": "issued", "pdfUrl": "https://invoices.example.com/INV-2026-00042.pdf" }
]

GET /v1/invoice-profiles/booking?isBookingPersonal=false lists the profiles
eligible for a booking's checkout context, matching the personal/business
split of the booking itself.

On that endpoint, isDefault is true on at most one profile: the one a
booking uses when it is created without an invoiceProfileId. Pre-select it in
checkout. When the requested scope (isBookingPersonal) has no profile, no
profile is the default, even if the other scope lists some. isDefault is
always present and is false on every other invoice-profile endpoint. The
isDefault you may send on create or update is accepted but ignored — it
cannot change which profile is the default.

When does an invoice profile edit reach a booking's invoice?

invoiceProfileId on POST /v1/{vertical}/bookings is a reference, chosen
once at booking create and not changeable afterward.

Whether a PATCH /v1/invoice-profiles/{id} made after a booking is
created — including appending an emailRecipients entry — is reflected in
that booking's invoice is not currently documented or guaranteed.
Do not design a flow that depends on a post-create profile edit reaching an
already-created booking's invoice; if the billing details need to be
correct for a specific booking, set them on the profile (or a
booking-specific profile) before that booking is created.

See the API Reference for the complete request and
response schemas, and Errors for
the full error envelope.

Reporting issues

This page is maintained by the BizAway integration team. To request changes or
report an error, contact your BizAway integration contact. Edits made directly
in the ReadMe dashboard are overwritten on the next publish.


Did this page help you?