myWebLog Mobile API v5

What it is

The Mobile API is what an app shows a member of an organization: their objects, bookings, flight log, balance and transactions, and the bookings they make. It is built on the same framework as the Main API v5: the same addresses, replies, errors and headers. What differs is who calls: an app, on behalf of one member, instead of an organization's own server.

The machine-readable description of the API is openapi.yaml (OpenAPI 3.0). The same endpoints are ready to try in Postman: import postman_collection.json.

Coming from v3? Moving from v3 to v5 lists every difference, function by function, with what to change.

Address

https://api.myweblog.se/mobile/v5/{resource}, for example https://api.myweblog.se/mobile/v5/me

One item is addressed by its id in the path, for example /objects/710. An address does not end with a slash: /me works, /me/ gives 404. A query parameter the endpoint does not know gives 400, so a misspelled filter is never silently ignored.

Two identities: the app and the member

The app is a client in the words of OAuth 2.1. A developer gets a client id from myWebLog (write to support@myweblog.se) and registers the app's redirect addresses. An app with a server of its own also gets a key, handed over through a link that works once; the key must be kept out of source code repositories and out of app binaries that users can unpack. An app without a server (a native iOS or Android app) gets no key: it is a public client, which identifies itself with its client id and PKCE. A client has rights per module, set by myWebLog, and can be limited to some organizations. myWebLog can revoke a key or a client; the app then stops working at once.

The member logs in on myWebLog's own login page, which the app opens in the phone's browser (OAuth 2.1: the authorization code flow with PKCE). The app never sees the password. The app gets an access token, valid an hour, and a refresh token, valid 90 days from its last use. The member sees the login on My settings on the website, next to the app's name, and can end it there. A password change ends every login.

Logging in (OAuth 2.1: the authorization code flow with PKCE)

This is the standard flow that AppAuth (iOS and Android), flutter_appauth, react-native-app-auth and every OAuth client library implement: give the library the authorization URL, the token URL, the client id, the redirect address and (for a client with a key) the client secret, and it does the steps below.

  1. The app makes a random code_verifier (43 to 128 characters of A-Z, a-z, 0-9, - . _ ~) and its code_challenge = BASE64URL(SHA-256(code_verifier)).
  2. The app opens GET /oauth/authorize?response_type=code&client_id=…&redirect_uri=…&code_challenge=…&code_challenge_method=S256&state=… in the system browser (ASWebAuthenticationSession on iOS, Custom Tabs on Android; never an embedded WebView). The API sends the browser to the login page on www.myweblog.se.
  3. The member logs in there and allows the app. The page sends the browser to redirect_uri?code=…&state=… (or error=access_denied if the member cancels). The app checks that state is its own.
  4. The app posts the code to /oauth/token with grant_type=authorization_code, redirect_uri, code_verifier and the client's credentials, within two minutes, and gets the tokens. A code works once.

POST /oauth/token takes the body as form data (application/x-www-form-urlencoded). A client with a key sends it in a Basic Authorization header (client_id:key) or as the fields client_id and client_secret; a public client sends client_id alone.

grant_type Fields Reply
authorization_code code, redirect_uri, code_verifier, and if you like device_name (what the member sees on My settings, such as the phone model) access_token, token_type, expires_in (3600), scope, refresh_token
refresh_token refresh_token A new access_token and a new refresh_token. The old refresh token is dead at once. Only the client that made the login can renew it.
client_credentials none An access_token for the app alone, good for GET /client only: "does my key work". Not for a public client, which has no key.

Every other call carries the access token: Authorization: Bearer [access token]. When it has expired the API answers 401 with WWW-Authenticate: Bearer error="invalid_token"; renew with the refresh token and retry. Renew when a call says so, not before every call.

Logging out: POST /oauth/revoke with the form field token = the refresh token (and the client's credentials). The refresh token and the access tokens fetched with it stop working. The reply is 200 also for a token that is already gone, so a logout never fails.

A code that is not valid, expired or already used gives 400 with error invalid_grant; so does a refresh token that is no longer valid, with an error_description meant for the app's user. Treat invalid_grant on a refresh as "logged out" and open the login again. The website's limits on failed logins apply on the login page. There is no password grant: OAuth 2.1 removed it, and no app, myWebLog's own included, ever handles a member's password. The replies of the /oauth endpoints follow the OAuth standard, not the Problem Details form of the other endpoints.

Redirect addresses: an https address the app has claimed (a universal link or Android app link) is safest; the app's own scheme in reverse-domain form (se.flygklubben.app:/oauth) also works. They are registered by myWebLog and compared exactly. For Postman, register https://oauth.pstmn.io/v1/callback.

In Postman: Authorization type OAuth 2.0, grant type Authorization Code (With PKCE), auth URL https://api.myweblog.se/mobile/v5/oauth/authorize, access token URL https://api.myweblog.se/mobile/v5/oauth/token, callback URL https://oauth.pstmn.io/v1/callback with "Authorize using browser" off, client ID (and client secret, for a client with a key; "Send as Basic Auth header"), code challenge method SHA-256. Get New Access Token opens the login page.

Sending data

POST and PATCH take a JSON object as the request body. The exceptions are the two /oauth endpoints, which take form data as the OAuth standard says. The id of the item is never in the body: it is in the address.

A value in the body has the same type as in a reply. Text is text: a member number is sent as "007", not as 7. An id is a number, yes or no is true or false, an amount is a number, a date is written "2026-09-30", and a point in time "2026-09-30T08:00:00Z" or with an offset, "2026-09-30T10:00:00+02:00". A value of another type gives 400. A field the endpoint does not know gives 400.

Headers

Header In Description
Authorization Request Required: Bearer [access token]. For the two /oauth endpoints: Basic [client_id:key in base64].
WWW-Authenticate Reply With 401: Bearer, and error="invalid_token" when the access token has expired or is not accepted (renew).
Request-Id Request and reply Optional. Your own id for the request, at most 64 characters. It is returned with the reply, and in the body of an error reply. If you send none, one is made for you. Quote it when you contact support.
RateLimit-Limit
RateLimit-Remaining
RateLimit-Reset
Reply Calls allowed per minute, calls left in the current minute, and seconds until the count starts over. For a member's token the member's figures (120 a minute); for a client's own token the client's (600 a minute over all its members, unless the client has a limit of its own). Both limits apply to every call.
Retry-After Reply With 429: seconds to wait before the next call.
Allow Reply With 405: the methods the address accepts.

Replies

A successful reply has the result under "data". An error reply follows the standard "Problem Details" (RFC 9457) and has the content type application/problem+json. "code" is the number in the error code table at the end of this page. "errors" is only present when the error is about named parameters or fields, or about booking rules (then without "field"):

{
  "type": "https://api.myweblog.se/errors/validation",
  "title": "The request has invalid parameters",
  "status": 400,
  "code": 10005,
  "request_id": "b7e2c41a9d0f3e55",
  "errors": [
    { "field": "verbose", "code": 10007, "message": "Unknown parameter" }
  ]
}

Lists

A list has its items under "data", and says where the page is in the list. limit says how many items to return (100 unless the endpoint says otherwise, at most 500), offset how many to skip. "has_more" says whether there are more items after the page, and "links.next" is the address of the next page. include_total=true also counts all the items that match, as "meta.total". The order of a list is fixed and given with each endpoint.

{
  "data": [ ... ],
  "meta": { "count": 20, "limit": 20, "offset": 0, "has_more": true },
  "links": { "next": "https://api.myweblog.se/mobile/v5/transactions?offset=20" }
}

include adds optional blocks to each item, separated by commas, where the endpoint has blocks (objects). exclude leaves out fields that an item always has, also separated by commas. A block or a field the endpoint does not have gives 400.

Endpoints

Click on an endpoint to see its details. "Right" is the module right the app's client needs for it; the member's token carries the client's rights.

token

GET
/oauth/authorize Sends the member's browser to myWebLog's login page, where the member logs in and allows the app (the authorization code flow).
Information Parameters Response

Opened in the system browser by the app (its OAuth library does it), not called from code. Answers 302 to the login page on www.myweblog.se with the same query string. The member logs in and allows the app there; the page then sends the browser to redirect_uri with code and state, or with error=access_denied when the member cancels.

The code is exchanged at POST /oauth/token with grant_type=authorization_code within two minutes, together with the code_verifier (PKCE) and the same redirect_uri. A code works once.

An unknown client id, or a redirect_uri that is not registered for the client, shows an error page on the website and never redirects.

response_type: code.
client_id: the app's client id.
redirect_uri: one of the app's registered redirect addresses, exactly as registered.
code_challenge: BASE64URL(SHA-256(code_verifier)). code_challenge_method: S256.
state: optional, returned unchanged; the app checks it is its own.
cl: optional, the language of the login page: se, gb, no or dk.

302 Found
POST
/oauth/token Exchanges the code for the member's tokens, renews a login, or gives the app a token of its own (OAuth 2.1).
Information Body Response

Called without a Bearer token. A client with a key sends its id and key in a Basic Authorization header (client_id:key in base64), which is what an OAuth client library does by itself, or as the form fields client_id and client_secret. A public client (no key) sends client_id alone.

grant_type=authorization_code logs the member in with the code from GET /oauth/authorize: the reply has access_token, token_type (Bearer), expires_in (3600), scope (the client's rights) and refresh_token. The code works once, within two minutes, for the client and redirect_uri it was made for, and only with the code_verifier its challenge was made from.

grant_type=refresh_token gives a new access token and a new refresh token; the old refresh token is dead at once. Renew when a call answers 401 with error="invalid_token", not before every call. Only the client that made the login can renew it.

grant_type=client_credentials gives an access token for the app alone, good for GET /client only. Not for a public client.

There is no grant_type=password (OAuth 2.1 removed it): it gets 400 unsupported_grant_type. A member's password is typed on myWebLog's login page only.

A code or refresh token that is not valid gives 400 with error invalid_grant and an error_description meant for the app's user, in the language of Accept-Language. The reply follows the OAuth 2.0 standard, not the Problem Details form of the other endpoints.

Form data (application/x-www-form-urlencoded), not JSON:

grant_type: authorization_code, refresh_token or client_credentials.
code, redirect_uri, code_verifier: with authorization_code. device_name is optional: what the member sees on My settings, such as the phone model.
refresh_token: with refresh_token.
client_id, client_secret: only when they are not sent in the Basic Authorization header. A public client sends client_id alone.

200 OK
POST
/oauth/revoke Logs the member out: the refresh token and the access tokens fetched with it stop working.
Information Body Response

Called with the client's credentials, as /oauth/token. The reply is 200 also for a token that is already gone, so a logout never fails. The login disappears from the member's My settings on the website.

Form data: token = the refresh token.

200 OK

client

GET
/client The app the access token belongs to: its rights and the organizations it is limited to. Also the way to test that a key works.
Information Parameters Response

The one endpoint that takes the app's own access token (grant_type=client_credentials) as well as a member's.

Returned: id, name (the developer), app_name (what members see on My settings), rights, organizations and rate_limit_per_minute. "rights" has one entry per module: "r" (read), "w" (write) or "rw". The modules are those of the Main API v5: organization, objects, bookings, flightlogs, transactions. "organizations" is null when the app may be used for every organization, otherwise a list of organization ids.

None
200 OK

me

GET
/me The member who is logged in: who they are, their organization and their balance.
Information Parameters Response

What version 3 gave as GetUserdata and GetBalance. Any member's token can call this.

Returned: id, username, member_number (text, since it can have leading zeros), name (first, prefix, last, full), user_category, locked, organization (id, name, homepage), balance (in the organization's currency) and currency (code, symbol).

"locked" true means the member may read but not book or change anything; such a call gives 403 with code 10302.

None
200 OK

organization

GET
/organization The member's organization: what an app needs to show times, money and bookings right.
Information Parameters Response

Right: organization:r. What version 3 sent as orgData with every reply; fetch it once per session.

Returned: id, name, homepage, location (reference_icao, latitude, longitude, country, timezone, utc_offset), date_format (as the website shows dates, in PHP's date() form), locale, currency (code, symbol) and booking (enabled, cancel_reason_required, standard_length_hours, use_expected_airborne).

"booking.enabled" is false when the organization has switched booking off; the booking endpoints then give 403 with code 10301, while everything else works. "utc_offset" is the offset right now; use "timezone" to work with other dates.

None
200 OK
GET
/organization/settings The settings the organization has marked "show in the app" on the website.
Information Parameters Response

Right: organization:r. What version 3 gave as GetOrgSettings. A list, each setting with "id" (the setting type), "value", "value_type" and the website's own fields for it, such as its description. The ids are the website's setting types, for example 1000 (hide the balance in the app's lobby) and 1001 (hide the transactions).

None
200 OK
GET
/sun-times Dawn, sunrise, sunset and dusk at the organization's reference airport, one item per date.
Information Parameters Response

Right: organization:r. Returned: airport (icao, latitude, longitude), timezone and days, one per date with date, utc_offset, dawn, sunrise, sunset and dusk. Each time is given in UTC ("at") and in the organization's time zone with its offset ("local"). Dawn and dusk are civil twilight. A time is null where the sun does not rise or set that day. "days" is empty when the organization has no coordinates.

date_from, date_to: the dates, inclusive. Today for a month when left out; at most 62 days.
200 OK

objects

GET
/objects What the member can book: aircraft, equipment and premises, the organization's own and the ones shared with it.
Information Parameters Blocks (include) Response

Right: objects:r. The objects as the booking calendar on the website shows them to this member, in the same order. What version 3 gave as GetObjects.

Always returned: id, registration, category (id and name: 0 Aircraft, 1 Equipment, 2 Premises), model (designator and name, only filled in for an aircraft), comment, organization (id and name of the owner) and has_thumbnail.

status: the object's status ids (0 OK, 1 yellow, 2 red) for the whole (total_id), for maintenance and for remarks, and remaining_time until maintenance is due ("soft") and until the object is grounded ("hard"), as numbers of hours and formatted. active_remarks: the open remarks on the object, each with id, created_date, created_by, description and category_id. time_summary: the object's total airborne, block and tach time (as numbers and formatted) and landings. disclaimer: a text the organization wants shown before the object is booked, { headline, text }, or null. settings: use_expected_airborne, force_expected_time and max_booking_length (minutes, or null).

status, active_remarks and time_summary are worked out the same way as on the website and take the longest to fetch, so ask only for the blocks you need.

limit, offset, include_total, exclude status
active_remarks
time_summary
disclaimer
settings
200 OK
GET
/objects/{id} One object.
Information Parameters Response

Right: objects:r. The same fields and blocks as in the list. 404 when the object is not one the member may see.

include, exclude
200 OK
GET
/objects/{id}/thumbnail The object's picture as a JPEG.
Information Parameters Response

Right: objects:r. 150 by 100 pixels, the reply body being the picture itself (Content-Type: image/jpeg), not JSON. The reply may be kept for a day (Cache-Control: private, max-age=86400) and carries an ETag. 404 with code 10304 when the object has no picture; "has_thumbnail" in the object says so beforehand.

None
200 OK

bookings

GET
/bookings The bookings the booking calendar on the website shows this member.
Information Filters Response

Right: bookings:r. In the website's order, with the bookings in the queue last. What version 3 gave as GetBookings.

Returned: id, start_at, end_at (UTC), start_local, end_local (the organization's time zone with its offset), timezone, object (id, registration, category, organization), user and student (id, name, member_number, email, mobile; student is null when the booking has none), type, is_primary, is_queue, is_own, is_student, is_active_now, is_passed, details_hidden, permissions (can_edit, can_cancel, can_cut, queue_allowed), expected_airborne, seats_left, comment, created_at and created_by.

The email and mobile number of the booker and the student follow each member's own settings on the website: null when hidden. "is_own" is true when the member is the booker or the student, "is_student" when the member is the student. "details_hidden" is true when the organization hides who has booked from other members; the names and contact details of such a booking are null, as in the booking calendar. "permissions" says what the member may do with the booking by the website's rules: change it, cancel it, cut it (end it now), and whether a queue booking on the object is allowed. "type" is the booking type as the website names it, such as PRIV or SKOL. Version 3 gave the times as Unix timestamps.

403 with code 10301 when the organization has switched booking off.

object_id (int): only bookings of this object
mine (bool): true gives only the member's own bookings, as booker or as student
date_from (date): bookings that end on or after this date; today when left out
date_to (date): bookings that start on or before this date

limit, offset, include_total, exclude
200 OK
GET
/bookings/{id} One booking, also one in the queue.
Information Parameters Response

Right: bookings:r. The same fields as in the list. 404 when it is not one the member may see.

exclude
200 OK
POST
/bookings A private booking for the member, by the website's booking rules.
Information Body Response

Right: bookings:w. Made through the website's booking class: the same rules as the booking calendar (who may book what, overlaps, the queue, lengths, balance) and the same messages. What version 3 did as CreateBooking. The booking type is always the member's own private booking (PRIV); school bookings and others are made on the website.

The reply is 201 with the booking as GET gives it under "data", a Location header with its address, and "messages": what the website would show the member after the booking, each as { "kind": "info", "text": "..." }, in the language of the Accept-Language header (sv, en, nb or da; English when left out).

When a booking rule stops it, the reply is 409 with code 10300 and the rule's text for the member in "errors" (see the examples). A locked member gets 403 with code 10302; an organization with booking switched off 403 with code 10301.

object_id (int), start_at, end_at: required. The times are points in time with their offset or Z, as the API gives them; the booking is made in the organization's time zone.

comment (text), expected_airborne (hours as a number, where the organization uses it) and seats_left (int, free seats offered to others): optional.

201 Created
POST
/bookings/{id}/cut Ends a booking that is going on, now.
Information Body Response

Right: bookings:w. What version 3 did as CutBooking. The booking's "permissions.can_cut" says beforehand whether the member may. 200 with the booking as it is afterwards and "messages"; 409 with code 10300 when a rule stops it (for one, a booking that has not started); 404 when the booking is not one the member may see.

None
200 OK
POST
/bookings/{id}/cancel Cancels the booking, which also sends the website's cancellation mails.
Information Body Response

Right: bookings:w. What version 3 did as DeleteBooking. "permissions.can_cancel" says beforehand whether the member may. 200 with the booking as it was, since it is gone afterwards, and "messages"; 409 with code 10300 when a rule stops it, also when a required reason is missing; 404 when the booking is not one the member may see.

reason (text): optional, { "reason": "Weather" }. Required when "booking.cancel_reason_required" on /organization is true.

200 OK

flightlogs

GET
/flightlogs The flights logged on the organization's objects and on the objects shared with it.
Information Filters Response

Right: flightlogs:r. Oldest first. What version 3 gave as GetFlightLog and, with order=desc, GetFlightLogReversed. The fields and their names are those of the Main API v5's flight log: id, date, object (id, registration, organization), flight_type (id, name, or null), departure and arrival (airport, blockoff_at, takeoff_at, landing_at, blockon_at), via_route, crew_hidden, pilot, instructor, scout (id, name, member_number, organization, or null), is_solo_instruction, totals (block, airborne, tach, as hours and as minutes), number_of_flights and comment.

The clock times are points in time in UTC. When the organization hides the pilot in its log, "crew_hidden" is true and "pilot", "instructor" and "scout" are null, as on the website; version 3 showed the names anyway. "is_solo_instruction" is true for a student's solo flight, false for a flight with an instructor, null when not filled in. A total is null when one of its two readings is missing. Version 3's "distance" is not given.

object_id (int): only flights on this object
mine (bool): true gives only the member's own flights, as pilot or as instructor
date_from, date_to (date): flights on these dates, inclusive
order: asc (oldest first, the default) or desc (newest first)

limit, offset, include_total, exclude
200 OK
GET
/flightlogs/{id} One logged flight.
Information Parameters Response

Right: flightlogs:r. The same fields as in the list. 404 when the flight is not on an object the member may see.

exclude
200 OK

transactions

GET
/transactions Charges to and payments into the member's account, newest first.
Information Filters Response

Right: transactions:r. 20 per page unless limit says otherwise. What version 3 gave as GetTransactions.

Returned: id, date, amount, comment, booked_by, balance_after and created_at. "balance_after" is the member's balance after the transaction. The list's "meta" also has "balance", the balance now over all transactions, and "opening_balance", the balance before the oldest transaction on the page. A "#" and what follows it in a comment is an internal note and is left out, as in version 3.

date_from (date): a year back when left out
date_to (date)

limit, offset, include_total, exclude
200 OK
GET
/transactions/{id} One transaction of the member.
Information Parameters Response

Right: transactions:r. The same fields as in the list. 404 when the transaction is not the member's.

exclude
200 OK

Examples

Login (cURL)

## 1. Open the login page in the browser (the app's library does this). {client_id} is the app's; the member logs in and allows the app there.
https://api.myweblog.se/mobile/v5/oauth/authorize?response_type=code&client_id={client_id}&redirect_uri={redirect_uri}&code_challenge={challenge}&code_challenge_method=S256&state={state}

## 2. The page sends the browser to {redirect_uri}?code={code}&state={state}. Exchange the code within two minutes. {key} only for a client that has one.
curl -u "{client_id}:{key}" \
  -d "grant_type=authorization_code" -d "code={code}" -d "redirect_uri={redirect_uri}" -d "code_verifier={verifier}" -d "device_name=iPhone 15" \
  https://api.myweblog.se/mobile/v5/oauth/token

## Then every call carries the access token.
curl -H "Authorization: Bearer {access_token}" https://api.myweblog.se/mobile/v5/me

## When a call answers 401 with error="invalid_token": renew. The old refresh token is dead afterwards.
curl -u "{client_id}:{key}" -d "grant_type=refresh_token" -d "refresh_token={refresh_token}" https://api.myweblog.se/mobile/v5/oauth/token

## Log out.
curl -u "{client_id}:{key}" -d "token={refresh_token}" https://api.myweblog.se/mobile/v5/oauth/revoke

Login reply

{
  "access_token": "mwlat_...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "organization:r objects:r bookings:rw flightlogs:r transactions:r",
  "refresh_token": "mwlrt_..."
}

GET me reply

{
  "data": {
    "id": 66311,
    "username": "3-anna",
    "member_number": "007",
    "name": { "first": "Anna", "prefix": "von", "last": "Berg", "full": "Anna von Berg" },
    "user_category": 2,
    "locked": false,
    "organization": { "id": 3, "name": "Svanshalls FK", "homepage": "https://www.svanshallsfk.se" },
    "balance": 150.5,
    "currency": { "code": "SEK", "symbol": "kr" }
  }
}

GET client reply

{
  "data": {
    "id": 4,
    "name": "Example Apps AB",
    "app_name": "Flyklubben",
    "rights": { "organization": "r", "objects": "r", "bookings": "rw", "flightlogs": "r", "transactions": "r" },
    "organizations": null,
    "rate_limit_per_minute": 600
  }
}

GET organization reply

{
  "data": {
    "id": 3,
    "name": "Svanshalls FK",
    "homepage": "https://www.svanshallsfk.se",
    "location": { "reference_icao": "ESMS", "latitude": 55.5363, "longitude": 13.3762, "country": "SWEDEN", "timezone": "Europe/Stockholm", "utc_offset": "+02:00" },
    "date_format": "Y-m-d",
    "locale": "sv_SE",
    "currency": { "code": "SEK", "symbol": "kr" },
    "booking": { "enabled": true, "cancel_reason_required": true, "standard_length_hours": 3.5, "use_expected_airborne": true }
  }
}

GET sun-times reply

{
  "data": {
    "airport": { "icao": "ESMS", "latitude": 55.5363, "longitude": 13.3762 },
    "timezone": "Europe/Stockholm",
    "days": [
      { "date": "2026-06-21", "utc_offset": "+02:00",
        "dawn": { "at": "2026-06-21T01:22:50Z", "local": "2026-06-21T03:22:50+02:00" },
        "sunrise": { "at": "2026-06-21T02:23:14Z", "local": "2026-06-21T04:23:14+02:00" },
        "sunset": { "at": "2026-06-21T19:53:36Z", "local": "2026-06-21T21:53:36+02:00" },
        "dusk": { "at": "2026-06-21T20:54:00Z", "local": "2026-06-21T22:54:00+02:00" } }
    ]
  }
}

GET objects request

https://api.myweblog.se/mobile/v5/objects?include=status,settings

GET objects reply

{
  "data": [
    { "id": 710, "registration": "SE-ABC", "category": { "id": 0, "name": "Aircraft" }, "model": { "designator": "C172", "name": "Cessna 172" },
      "comment": "Club aircraft", "organization": { "id": 3, "name": "Svanshalls FK" }, "has_thumbnail": true,
      "status": { "total_id": 1, "maintenance_id": 1, "remarks_id": 0,
        "remaining_time": { "soft_airborne": 12.5, "soft_airborne_formatted": "12:30", "hard_airborne": 22.5, "hard_airborne_formatted": "22:30" } },
      "settings": { "use_expected_airborne": true, "force_expected_time": false, "max_booking_length": null } }
  ],
  "meta": { "count": 1, "limit": 100, "offset": 0, "has_more": false },
  "links": { "next": null }
}

GET bookings request

https://api.myweblog.se/mobile/v5/bookings?date_from=2026-10-04&date_to=2026-10-04

GET bookings reply

{
  "data": [
    { "id": 4711, "start_at": "2026-10-04T08:00:00Z", "end_at": "2026-10-04T10:00:00Z",
      "start_local": "2026-10-04T10:00:00+02:00", "end_local": "2026-10-04T12:00:00+02:00", "timezone": "Europe/Stockholm",
      "object": { "id": 710, "registration": "SE-ABC", "category": { "id": 0, "name": "Aircraft" }, "organization": { "id": 3 } },
      "user": { "id": 66311, "name": "Anna von Berg", "member_number": "007", "email": "anna@example.com", "mobile": "+46 70 123 45 67" },
      "student": null,
      "type": "PRIV", "is_primary": true, "is_queue": false, "is_own": true, "is_student": false, "is_active_now": false, "is_passed": false, "details_hidden": false,
      "permissions": { "can_edit": true, "can_cancel": true, "can_cut": false, "queue_allowed": true },
      "expected_airborne": 1.5, "seats_left": 2, "comment": "Local flight", "created_at": "2026-10-01T09:00:00Z", "created_by": "Anna von Berg" }
  ],
  "meta": { "count": 1, "limit": 100, "offset": 0, "has_more": false },
  "links": { "next": null }
}

POST bookings request

{
  "object_id": 710,
  "start_at": "2026-10-10T08:00:00Z",
  "end_at": "2026-10-10T12:00:00+02:00",
  "comment": "Local flight",
  "expected_airborne": 1.5,
  "seats_left": 2
}

POST bookings reply (201)

{
  "data": { "id": 4712, "start_at": "2026-10-10T08:00:00Z", "end_at": "2026-10-10T10:00:00Z", ... },
  "messages": [ { "kind": "info", "text": "Remember to fill in the expected airborne time." } ]
}

Reply when a booking rule stops the action

{
  "type": "https://api.myweblog.se/errors/conflict",
  "title": "A booking rule stopped the action",
  "status": 409,
  "code": 10300,
  "request_id": "b7e2c41a9d0f3e55",
  "errors": [ { "code": 10300, "message": "The object is already booked at that time." } ]
}

GET flightlogs reply

{
  "data": [
    { "id": 88, "date": "2026-10-03", "object": { "id": 710, "registration": "SE-ABC", "organization": { "id": 3, "name": "Svanshalls FK" } },
      "flight_type": { "id": 2, "name": "School" },
      "departure": { "airport": { "icao": "ESMS", "name": "Malmö" }, "blockoff_at": "2026-10-03T09:10:00Z", "takeoff_at": "2026-10-03T09:20:00Z" },
      "via_route": null,
      "arrival": { "airport": { "icao": "ESSA", "name": "Arlanda" }, "landing_at": "2026-10-03T11:10:00Z", "blockon_at": "2026-10-03T11:20:00Z" },
      "crew_hidden": false,
      "pilot": { "id": 66311, "name": "Anna von Berg", "member_number": "007", "organization": { "id": 3, "name": "Svanshalls FK" } },
      "instructor": null, "scout": null, "is_solo_instruction": false,
      "totals": { "block": 2.17, "block_minutes": 130, "airborne": 1.83, "airborne_minutes": 110, "tach": 1.9, "tach_minutes": 114 },
      "number_of_flights": 1, "comment": "Night" }
  ],
  "meta": { "count": 1, "limit": 100, "offset": 0, "has_more": false },
  "links": { "next": null }
}

GET transactions reply

{
  "data": [
    { "id": 903, "date": "2026-10-05", "amount": -0.7, "comment": "Landing", "booked_by": "Eva Admin via API", "balance_after": 170.5, "created_at": "2026-10-05T12:00:00Z" }
  ],
  "meta": { "count": 1, "limit": 20, "offset": 0, "has_more": true, "balance": 150.5, "opening_balance": 171.2 },
  "links": { "next": "https://api.myweblog.se/mobile/v5/transactions?offset=20" }
}

Error Codes

"code" in an error reply is one of these numbers. Codes up to 10199 are the same as in the Main API v5; codes from 10300 are the Mobile API's own. The /oauth endpoints answer with the OAuth error form instead, except 429 and 500.

Code Name Comment Response
10000 HTTPS is required A call over plain HTTP is normally redirected to HTTPS by the server before it reaches the API.
403 Forbidden
10001 Unauthorized The access token is missing, not accepted, or has expired (then WWW-Authenticate has error="invalid_token": renew). Also when the login has been ended, the member is no longer active, or the client or its key has been revoked.
401 Unauthorized
10002 No access to the module The client lacks the read or write right the endpoint needs. Ask myWebLog to change the client's rights.
403 Forbidden
10003 The address is blocked The IP address is on myWebLog's block list.
403 Forbidden
10004 The request body must be a JSON object The body of a POST or PATCH could not be read as JSON.
400 Bad Request
10005 Invalid parameter A query parameter has the wrong form. "errors" names it.
400 Bad Request
10006 Invalid field A field of the body is missing or has the wrong type or form. "errors" names each field.
400 Bad Request
10007 Unknown parameter or field The endpoint does not have the named query parameter or body field. Check the spelling.
400 Bad Request
10010 Internal error A database error on our side. It has been logged. Nothing was saved.
500 Internal Server Error
10012 Too many failed login attempts The username or the IP address has too many failed logins lately, on the website or here. Wait Retry-After seconds.
429 Too Many Requests
10013 Too many requests The member (120 a minute) or the client (600 a minute) has made too many calls. Wait Retry-After seconds.
429 Too Many Requests
10014 Too many failed authorization attempts Too many wrong client credentials from the IP address. Wait Retry-After seconds.
429 Too Many Requests
10020 Internal error Something unexpected on our side. It has been logged; quote the request id to support.
500 Internal Server Error
10050 Method not allowed The address exists but not with this method. The Allow header says which methods it accepts.
405 Method Not Allowed
10100 Not found The address or the item does not exist.
404 Not Found
10302 The member is locked A locked member may read but not change anything.
403 Forbidden
10300 A booking rule stopped the action The website's booking rules do not allow it. "errors" has the rule's text for the member.
409 Conflict
10301 Booking is switched off The organization has switched booking off; everything but the booking endpoints works.
403 Forbidden
10304 The object has no thumbnail "has_thumbnail" in the object says beforehand whether there is one.
404 Not Found
10305 A member's access token is needed The token is the client's own (grant_type=client_credentials), which only GET /client takes. Log a member in.
403 Forbidden