ExpensesUpdate a mileage registration

Update a mileage registration

Replaces the trip details of an unapproved, uninvoiced mileage registration, optionally updating or removing its travel time.

A full replacement (PUT) addressed by MileageRegistrationID in the body: every field of the body overwrites the stored value, so read the registration first and send everything back. Owner and contract cannot be changed; a project change keeps the old contract. Send TravelTimeRegistration to update the linked travel time (or create one), or ?deleteTravelTimeRegistration=true to unlink and delete it. Returns the updated registration.

Use it to:

  • Employee correcting a trip (distance, addresses, purpose) before approval
  • Adding travel time to an existing trip

Not for:

  • Changing the owner or the contract — delete and re-create
  • Approving — not available in this API

Rules across fields:

  • R1: TravelTimeRegistration.TaskID must be a task of ProjectID.
  • R2: When ShowOdometer is on and either odometer is sent, OdometerEnd ≥ OdometerStart (400); with OdometerIsRequired also on, Distance × (IsRoundtrip ? 2 : 1) = OdometerEnd − OdometerStart.
  • R3: MileageRateID must have a rate period covering Date.
  • R4: A personal CarID must belong to the registration's owner.

Behaviour:

  • Idempotent.
  • Same body → same stored values (last write wins, no concurrency token). With TravelTimeRegistration on a mileage that has none, the FIRST call creates a time registration and later calls update it.
  • Safe to retry.
  • Duplicates: n/a
  • Side effect: With TravelTimeRegistration: updates (or creates and links) the travel-time registration — task, hours, date, Purpose as comment.
  • Side effect: With ?deleteTravelTimeRegistration=true: unlinks the travel-time registration, saves the mileage, then deletes the time registration.
  • On failure: Travel-time changes are compensated, not transactional: the previous time registration is re-saved (or the new one deleted) when the mileage save throws; if time-registration delete fails after unlinking, the mileage is re-saved with the link.
  • Changes are visible to the next read immediately.

Call first: GET /v1/mileage-registration/{mileageRegistrationID}

Next: GET /v1/mileage-registration/{mileageRegistrationID}

See also: DELETE /v1/mileage-registration/{mileageRegistrationID}

Not yet documented: examples.

curl -X PUT "https://app3.timelog.com/your-account/api/v1/mileage-registration?deleteTravelTimeRegistration=false" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -d '{
  "MileageRegistrationID": 123,
  "Date": "2024-12-25T10:00:00Z",
  "Purpose": "example_string",
  "OdometerStart": "null",
  "OdometerEnd": "null",
  "Distance": 42,
  "StartAddress": "123 Main St",
  "EndAddress": "123 Main St",
  "ProjectID": 123,
  "CarID": 123,
  "MileageRateID": 123,
  "IsRoundtrip": true,
  "IsBillable": true,
  "TravelTimeRegistration": {
    "TaskID": 123,
    "Hours": 3.14,
    "Minutes": 42
  }
}'
{
  "Properties": {
    "MileageRegistrationID": 123,
    "ID": "123e4567-e89b-12d3-a456-426614174000",
    "Date": "2024-12-25T10:00:00Z",
    "Purpose": "example_string",
    "OdometerStart": "null",
    "OdometerEnd": "null",
    "Distance": 42,
    "UnitType": 42,
    "TotalDistance": 3.14,
    "IsRoundtrip": true,
    "StartAddress": "123 Main St",
    "EndAddress": "123 Main St",
    "ProjectID": 123,
    "ProjectSubContractID": 123,
    "UserID": 123,
    "CarID": 123,
    "MileageRatesID": 123,
    "IsBillable": true,
    "IsApproved": true,
    "IsInvoiced": true,
    "InterfaceCreated": 42,
    "InterfaceModified": 42,
    "Project": {
      "ProjectID": 123,
      "ID": "123e4567-e89b-12d3-a456-426614174000",
      "Name": "John Doe",
      "No": "example_string",
      "ExpenseIsBillable": "null",
      "CustomerID": 123,
      "Customer": {
        "CustomerID": 123,
        "ID": "123e4567-e89b-12d3-a456-426614174000",
        "Name": "John Doe",
        "No": "example_string",
        "DefaultMileageDistance": 25,
        "CustomerStatusID": 123,
        "VATNo": "example_string",
        "OrganizationNo": "example_string"
      },
      "MainContractId": 123
    },
    "Car": {
      "CarID": 123,
      "ID": "123e4567-e89b-12d3-a456-426614174000",
      "Name": "John Doe",
      "LicensePlate": "example_string",
      "CarType": 42,
      "EmployeeUserID": "null",
      "EmployeeUser": {
        "UserID": 123,
        "ID": "123e4567-e89b-12d3-a456-426614174000",
        "FirstName": "John Doe",
        "LastName": "John Doe",
        "Initials": "example_string",
        "IsActive": true,
        "UserType": "Employee",
        "LegalEntityID": 123,
        "Email": "user@example.com"
      },
      "IsActive": true,
      "DefaultMileageRate": {
        "ID": "123e4567-e89b-12d3-a456-426614174000",
        "MileageRateID": 123,
        "Name": "John Doe",
        "IsActive": true,
        "SalaryCodeTaxFree": "null",
        "SalaryCodeTaxable": "null",
        "AccountNumber": "null",
        "IsDefaultForPrivateCar": true,
        "HasReimbursement": true,
        "UnitType": 42,
        "ReimbursementCurrencyID": 123,
        "LegalEntityID": 123
      },
      "IsDefault": true,
      "AllowEmployeeChangeMileageRate": true
    },
    "MileageRate": {
      "ID": "123e4567-e89b-12d3-a456-426614174000",
      "MileageRateID": 123,
      "Name": "John Doe",
      "IsActive": true,
      "SalaryCodeTaxFree": "null",
      "SalaryCodeTaxable": "null",
      "AccountNumber": "null",
      "IsDefaultForPrivateCar": true,
      "HasReimbursement": true,
      "UnitType": 42,
      "ReimbursementCurrencyID": 123,
      "LegalEntityID": 123
    },
    "TravelTimeRegistration": {
      "TimeRegistrationID": 123,
      "TaskID": 123,
      "Hours": 3.14,
      "Minutes": 42,
      "Comment": "null"
    }
  },
  "Links": [
    {
      "Href": "example_string",
      "Rel": "example_string"
    }
  ],
  "Actions": [
    {}
  ]
}
PUT
/v1/mileage-registration
PUT
Base URLstring

Target server for requests. Edit to use your own host.

Bearer Token
Bearer Tokenstring
Required

OAuth 2.0 bearer token, sent as Authorization: Bearer <token>. JWT and reference tokens are both accepted. The token must carry the required scope (default tlp). The token's sub claim is the acting user. A token WITHOUT sub (client-credentials) acts as the system service user. If the sub user cannot log in (inactive, locked, deleted), the request is rejected with 401 — it is no longer let through without a user. > Not yet documented: how to obtain a token. > Not yet documented: token lifetime.

OAuth 2.0 bearer token, sent as Authorization: Bearer <token>. JWT and reference tokens are both accepted. The token must carry the required scope (default tlp). The token's sub claim is the acting user. A token WITHOUT sub (client-credentials) acts as the system service user. If the sub user cannot log in (inactive, locked, deleted), the request is rejected with 401 — it is no longer let through without a user. > Not yet documented: how to obtain a token. > Not yet documented: token lifetime.
query
deleteTravelTimeRegistrationboolean

true = unlink AND delete the linked travel-time registration (ignored when the body carries TravelTimeRegistration, or when none is linked).

Content-Typestring
Required

The media type of the request body

Options: application/json
MileageRegistrationIDinteger

The registration to update. Identifier of this object, unique per TimeLog site. - 0 — 400, Code 200. - unknown or negative — 500, Code 100.

Format: int32
Datestring

The trip date. Time zone: not yet documented. - in a closed accounting period of the owner — 37827. - no rate period of MileageRateID covers it — 37845. > Not yet documented: constraints → timezone.

Format: date-time
Purposestring

Why the trip was made. - omitted, empty or whitespace — Not checked by the 400 validator; the domain raises 60107 (HTTP 500, Code 102).

Max length: 255
OdometerStartintegernull

Odometer reading at the start (km). Omitting it clears the stored value. Null: null / omitted = cleared Unit: km

Format: int32
OdometerEndintegernull

Odometer reading at the end (km). Omitting it clears the stored value. Null: null / omitted = cleared Unit: km - both odometers sent, ShowOdometer and OdometerIsRequired on, and Distance × (IsRoundtrip ? 2 : 1) ≠ OdometerEnd − OdometerStart — 60100.

Format: int32
Distanceinteger

One-way distance in whole km. TotalDistance is recalculated (× 2 when IsRoundtrip). Unit: km - ≤ 0 or omitted — The update validator's NotNull on an int never fires; the domain raises 60103 (HTTP 500, Code 102), not 400 as on create. Range: min 1.

Format: int32 • Min: 1
StartAddressstring

Where the trip started.

Max length: 255
EndAddressstring

Where the trip ended.

Max length: 255
ProjectIDinteger

The project. Changeable, but the stored contract is NOT re-resolved. Refers to ProjectHeaderRead.ProjectID. Look up valid values with GET /v1/project-header/search-for-expense-travel-registration-order-by-recent-registration. - changed to another project — ProjectSubContractID keeps the old project's contract; the contract rule only checks that contract is not closed (37846). Valid values come from GET /v1/project-header/search-for-expense-travel-registration-order-by-recent-registration.

Format: int32
CarIDinteger

The car used. A personal car must belong to the registration's owner. Refers to CarRead.CarID. Look up valid values with GET /v1/car. - personal car of another employee — 37932. Valid values come from GET /v1/car.

Format: int32
MileageRateIDinteger

The mileage rate (returned as MileageRatesID on reads). Must have a rate period covering Date. Refers to MileageRateRead.MileageRateID. Look up valid values with GET /v1/mileage-rate.

Format: int32
IsRoundtripboolean

true = there and back (TotalDistance = Distance × 2).

IsBillableboolean

Whether the mileage is invoiced to the customer.

TravelTimeRegistrationobject

Optional travel time to create or update together with the mileage. - sent and the mileage already has a travel-time registration — That time registration is updated (task, hours, date, comment) BEFORE the mileage is validated; on a mileage failure it is re-saved with its previous values. - sent and the mileage has none — A new travel-time registration is created and linked; deleted again if the mileage save fails. - sent together with ?deleteTravelTimeRegistration=true — The body wins; the query flag is ignored. - omitted — An existing travel-time registration is left unchanged (unless ?deleteTravelTimeRegistration=true).

Request Preview
Response

Response will appear here after sending the request

Authentication

header
Authorizationstring
Required

Bearer token. OAuth 2.0 bearer token, sent as Authorization: Bearer <token>. JWT and reference tokens are both accepted. The token must carry the required scope (default tlp).

The token's sub claim is the acting user. A token WITHOUT sub (client-credentials) acts as the system service user. If the sub user cannot log in (inactive, locked, deleted), the request is rejected with 401 — it is no longer let through without a user.

Not yet documented: how to obtain a token.

Not yet documented: token lifetime.

Query Parameters

deleteTravelTimeRegistrationboolean

true = unlink AND delete the linked travel-time registration (ignored when the body carries TravelTimeRegistration, or when none is linked).

Body

application/json
MileageRegistrationIDinteger

The registration to update.

Identifier of this object, unique per TimeLog site.

  • 0 — 400, Code 200.

  • unknown or negative — 500, Code 100.

Datestring

The trip date.

Time zone: not yet documented.

  • in a closed accounting period of the owner — 37827.

  • no rate period of MileageRateID covers it — 37845.

Not yet documented: constraints → timezone.

Purposestring

Why the trip was made.

  • omitted, empty or whitespace — Not checked by the 400 validator; the domain raises 60107 (HTTP 500, Code 102).
OdometerStartinteger,null

Odometer reading at the start (km). Omitting it clears the stored value.

Null: null / omitted = cleared

Unit: km

OdometerEndinteger,null

Odometer reading at the end (km). Omitting it clears the stored value.

Null: null / omitted = cleared

Unit: km

  • both odometers sent, ShowOdometer and OdometerIsRequired on, and Distance × (IsRoundtrip ? 2 : 1) ≠ OdometerEnd − OdometerStart — 60100.
Distanceinteger

One-way distance in whole km. TotalDistance is recalculated (× 2 when IsRoundtrip).

Unit: km

  • ≤ 0 or omitted — The update validator's NotNull on an int never fires; the domain raises 60103 (HTTP 500, Code 102), not 400 as on create.

Range: min 1.

StartAddressstring

Where the trip started.

EndAddressstring

Where the trip ended.

ProjectIDinteger

The project. Changeable, but the stored contract is NOT re-resolved.

Refers to ProjectHeaderRead.ProjectID. Look up valid values with GET /v1/project-header/search-for-expense-travel-registration-order-by-recent-registration.

  • changed to another project — ProjectSubContractID keeps the old project's contract; the contract rule only checks that contract is not closed (37846).

Valid values come from GET /v1/project-header/search-for-expense-travel-registration-order-by-recent-registration.

CarIDinteger

The car used. A personal car must belong to the registration's owner.

Refers to CarRead.CarID. Look up valid values with GET /v1/car.

  • personal car of another employee — 37932.

Valid values come from GET /v1/car.

MileageRateIDinteger

The mileage rate (returned as MileageRatesID on reads). Must have a rate period covering Date.

Refers to MileageRateRead.MileageRateID. Look up valid values with GET /v1/mileage-rate.

IsRoundtripboolean

true = there and back (TotalDistance = Distance × 2).

IsBillableboolean

Whether the mileage is invoiced to the customer.

TravelTimeRegistrationobject

Optional travel time to create or update together with the mileage.

  • sent and the mileage already has a travel-time registration — That time registration is updated (task, hours, date, comment) BEFORE the mileage is validated; on a mileage failure it is re-saved with its previous values.

  • sent and the mileage has none — A new travel-time registration is created and linked; deleted again if the mileage save fails.

  • sent together with ?deleteTravelTimeRegistration=true — The body wins; the query flag is ignored.

  • omitted — An existing travel-time registration is left unchanged (unless ?deleteTravelTimeRegistration=true).

Responses

Propertiesobject

A mileage (car travel) registration: the trip (date, purpose, addresses, one-way distance, round-trip flag, odometer readings), the project and contract it is booked on, the owner (UserID), car and mileage rate, approval / invoicing state, and the optional linked travel-time registration. Money is not on this object — the reimbursement and invoice amounts are derived from TotalDistance and the mileage rate's period rates. Nested Project, Car and MileageRate are filled only on $expand. Each entity carries a self link to GET /v1/mileage-registration/{id} and the mileage TAF actions.

Linksarray
Actionsobject[]