aauneAdd your business

Aune API

Confirm real service bookings from any agent.

Search provider, fixed-price, and slot combinations with postcodes but without street address or customer contact data. Confirm the exact option only after user choice, consent, and terms acceptance. Fall back to provider follow-up when no option exists.

Base URLhttps://aune-homepage-chat.vercel.app
Canonical prefix/v1
Booking contractpublic_bookings_api_v1
Bookable todayPlumbing/VVS, Electricians, Moving, Cleaning
Write authOAuth 2.1 with narrow scopes
Truth ruleFour explicit confirmation signals

Authorization

Give agents only the power they need.

User-delegated writes use Authorization Code with PKCE S256 and exact OAuth scopes. Public search stays data-minimized. Partner credentials are a separate server-to-server product and must not be exposed in clients.

GET/v1/capabilities

Read live capabilities

Returns supported verticals, job type IDs, required fields, geographic scope, and non-bookable future verticals.

POST/v1/booking-options

Search with minimal location data

Checks current provider eligibility, provider-owned fixed price, and concrete slots. Returns short-lived option IDs and exact terms versions.

POST/v1/bookings

Confirm the chosen option

Revalidates provider, price, slot, consent, terms, and idempotency before creating a durable confirmed booking and calendar entry.

GET/v1/bookings/{booking_id}

Read booking status

Returns redacted provider, slot, price, terms version, and lifecycle status without customer contact PII.

POST/v1/bookings/{booking_id}/cancel

Cancel after fresh confirmation

Cancels the durable booking idempotently after the user explicitly confirms the destructive action.

POST/v1/bookings/{booking_id}/reschedule

Reschedule to a fresh option

Revalidates a newly searched provider option, slot, price, postcodes, consent, and exact terms before moving the booking.

POST/v1/requests

Fallback to provider follow-up

Creates a structured request after consent when no direct option exists. This endpoint does not confirm provider, availability, slot, booking, or final price.

Quickstart

Search before collecting contact details.

Capabilities define the current taxonomy. Booking search then checks real provider price and slot supply without customer contact details.

curl capabilities
curl "$AUNE_BASE_URL/v1/capabilities"
curl booking search
curl -X POST "$AUNE_BASE_URL/v1/booking-options" \
  -H "Content-Type: application/json" \
  --data '{
  "spec_version": "public_bookings_api_v1",
  "vertical_id": "moving",
  "job_type_id": "moving_home",
  "description": "Home move tomorrow afternoon from postcode 111 20 to 118 20. The apartment is 45 sqm with about 25 boxes, a sofa, and a bed. Both addresses have elevators.",
  "location": {
    "country_code": "SE",
    "postcode": "111 20",
    "city": "Stockholm"
  },
  "destination_location": {
    "country_code": "SE",
    "postcode": "118 20",
    "city": "Stockholm"
  },
  "timing": {
    "preferred_time_text": "Tomorrow afternoon"
  },
  "details": {
    "home_size_sqm": 45,
    "boxes": 25,
    "elevator_origin": true,
    "elevator_destination": true
  },
  "locale": "sv-SE",
  "timezone": "Europe/Stockholm"
}'
curl request fallback
curl -X POST "$AUNE_BASE_URL/v1/requests" \
  -H "Authorization: Bearer $AUNE_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: partner-case-123" \
  --data '{
  "spec_version": "public_requests_api_v1",
  "vertical_id": "vvs",
  "job_type_id": "leak_faucet_fixture",
  "description": "Kitchen faucet leaks when used. Customer wants help next week.",
  "user_consent_confirmed": true,
  "user_consent_statement": "The customer agreed that Aune may receive their contact details and request details for provider follow-up.",
  "consent_source": "external_model_conversation",
  "customer": {
    "name": "Anna Andersson",
    "phone": "0701234567",
    "email": "anna@example.se"
  },
  "location": {
    "input": "Storgatan 12, 118 61 Stockholm"
  },
  "timing": {
    "preferred_time_text": "Next Friday morning"
  },
  "budget_sek": 4500,
  "details": {
    "fixture": "kitchen faucet"
  },
  "source": "external_model",
  "external_reference": "partner-case-123",
  "idempotency_key": "partner-case-123",
  "locale": "sv-SE",
  "timezone": "Europe/Stockholm"
}'

Examples

One booking contract across REST and MCP.

Both surfaces use postcode-only search followed by an authenticated confirmation carrying the unchanged option, consent evidence, exact terms version, and idempotency key.

TypeScript fetch
const baseUrl = process.env.AUNE_BASE_URL ?? "https://aune-homepage-chat.vercel.app";

const search = await fetch(`${baseUrl}/v1/booking-options`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    "spec_version": "public_bookings_api_v1",
    "vertical_id": "moving",
    "job_type_id": "moving_home",
    "description": "Home move tomorrow afternoon from postcode 111 20 to 118 20. The apartment is 45 sqm with about 25 boxes, a sofa, and a bed. Both addresses have elevators.",
    "location": {
      "country_code": "SE",
      "postcode": "111 20",
      "city": "Stockholm"
    },
    "destination_location": {
      "country_code": "SE",
      "postcode": "118 20",
      "city": "Stockholm"
    },
    "timing": {
      "preferred_time_text": "Tomorrow afternoon"
    },
    "details": {
      "home_size_sqm": 45,
      "boxes": 25,
      "elevator_origin": true,
      "elevator_destination": true
    },
    "locale": "sv-SE",
    "timezone": "Europe/Stockholm"
  }),
}).then((response) => response.json());

if (!search.direct_booking_available) {
  console.log(search.fallback);
  process.exit(0);
}

const option = search.options[0]; // Present options and let the user choose.
const response = await fetch(`${baseUrl}/v1/bookings`, {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.AUNE_ACCESS_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    spec_version: "public_bookings_api_v1",
    booking_option_id: option.booking_option_id,
    customer: {
      name: "Example Customer",
      phone: "+46700000000",
      email: "customer@example.invalid",
    },
    service_location: {
      country_code: "SE",
      address: "Examplegatan 1",
      postcode: "111 20",
    },
    destination_location: {
      country_code: "SE",
      address: "Exempelvagen 2",
      postcode: "118 20",
    },
    user_consent_confirmed: true,
    booking_terms_accepted: true,
    booking_terms_version: option.terms.version,
    booking_terms_accepted_at: new Date().toISOString(),
    idempotency_key: "conversation-123-option-1",
  }),
});

const result = await response.json();
Python requests
import json
import os
import requests

base_url = os.getenv("AUNE_BASE_URL", "https://aune-homepage-chat.vercel.app")
token = os.environ["AUNE_ACCESS_TOKEN"]

search_payload = json.loads(r'''{
  "spec_version": "public_bookings_api_v1",
  "vertical_id": "moving",
  "job_type_id": "moving_home",
  "description": "Home move tomorrow afternoon from postcode 111 20 to 118 20. The apartment is 45 sqm with about 25 boxes, a sofa, and a bed. Both addresses have elevators.",
  "location": {
    "country_code": "SE",
    "postcode": "111 20",
    "city": "Stockholm"
  },
  "destination_location": {
    "country_code": "SE",
    "postcode": "118 20",
    "city": "Stockholm"
  },
  "timing": {
    "preferred_time_text": "Tomorrow afternoon"
  },
  "details": {
    "home_size_sqm": 45,
    "boxes": 25,
    "elevator_origin": true,
    "elevator_destination": true
  },
  "locale": "sv-SE",
  "timezone": "Europe/Stockholm"
}''')
search = requests.post(
    f"{base_url}/v1/booking-options",
    json=search_payload,
    timeout=20,
).json()

if not search["direct_booking_available"]:
    print(search["fallback"])
    raise SystemExit(0)

option = search["options"][0]  # Present options and let the user choose.
payload = {
    "spec_version": "public_bookings_api_v1",
    "booking_option_id": option["booking_option_id"],
    "customer": {
        "name": "Example Customer",
        "phone": "+46700000000",
        "email": "customer@example.invalid",
    },
    "service_location": {
        "country_code": "SE",
        "address": "Examplegatan 1",
        "postcode": "111 20",
    },
    "destination_location": {
        "country_code": "SE",
        "address": "Exempelvagen 2",
        "postcode": "118 20",
    },
    "user_consent_confirmed": True,
    "booking_terms_accepted": True,
    "booking_terms_version": option["terms"]["version"],
    "booking_terms_accepted_at": "2026-07-10T10:00:00.000Z",
    "idempotency_key": "conversation-123-option-1",
}

response = requests.post(
    f"{base_url}/v1/bookings",
    headers={
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
    },
    json=payload,
    timeout=20,
)
response.raise_for_status()
print(response.json())
Cleaning request fallback
{
  "spec_version": "public_requests_api_v1",
  "vertical_id": "cleaning",
  "job_type_id": "cleaning_move_out",
  "description": "Move-out cleaning for an empty 82 sqm apartment next Friday.",
  "user_consent_confirmed": true,
  "user_consent_statement": "The customer agreed that Aune may receive their contact details and request details for provider follow-up.",
  "consent_source": "external_model_conversation",
  "customer": {
    "name": "Anna Andersson",
    "phone": "0701234567",
    "email": "anna@example.se"
  },
  "location": {
    "input": "Storgatan 12, 118 61 Stockholm"
  },
  "timing": {
    "preferred_time_text": "Next Friday morning"
  },
  "details": {
    "square_meters": 82,
    "move_state": "empty"
  },
  "source": "external_model",
  "external_reference": "partner-cleaning-123",
  "idempotency_key": "partner-cleaning-123",
  "locale": "sv-SE",
  "timezone": "Europe/Stockholm"
}

Responses

Confirmation is explicit and inspectable.

A booking exists only when all three truth flags are true and `booking.status` is `confirmed`. Notification delivery is reported separately and never defines whether the booking exists.

201 confirmed booking
{
  "ok": true,
  "spec_version": "public_bookings_api_v1",
  "request_id": "nvr_booking_...",
  "booking": {
    "id": "network_...",
    "status": "confirmed",
    "provider_name": "Example Moving AB",
    "service_id": "moving_home_starter_3h",
    "slot_start_at": "2026-07-11T13:00:00.000Z",
    "slot_end_at": "2026-07-11T16:00:00.000Z",
    "price_sek": 2800,
    "currency": "SEK",
    "terms_version": "fixed_price_terms_v1:moving_home_starter_3h"
  },
  "booking_created": true,
  "availability_checked": true,
  "provider_selected": true,
  "idempotent_replay": false,
  "safe_next_step": "Tell the user the booking is confirmed."
}

Errors

Failures have a recovery contract.

Errors use RFC problem details and every response carries request, trace, contract, and server-time metadata.

400/422

Fix invalid input; do not retry unchanged.

401/403

Refresh authorization or request the missing scope.

404

Verify opaque ID and authenticated principal.

409

Preserve idempotency or search a fresh option as instructed.

429/5xx

Obey Retry-After and retry writes only with the same key.