VACATION_INCENTIVES_MOBILE_API

Graphical reference view with linked API documentation.

Vacation incentives engine — mobile API

This document is the integration contract for native apps to use the same vacation incentive / redeem flow as the web portal: catalog + provider-backed issuance, plus the user vacation pool ledger (POS credits, etc.).

Base URL: your portal origin, e.g. https://<tenant-domain> (or the shared API host if you call a central domain).

API prefix: https://<host>/api
Stable (versioned) surface: https://<host>/api/v1/...prefer this for new mobile work.

Index: docs/api/README.md · Authentication · Hotels (tenant engine) · Developer UI in the app.

All JSON APIs should send:

  • Accept: application/json
    (Without it, unauthenticated calls may return an HTML login redirect instead of 401 JSON.)

Authentication (Laravel Sanctum)

Mobile clients obtain a Bearer token and send it on protected routes:

Authorization: Bearer <access_token>

Issue token

Method Path Auth
POST /api/v1/auth/token No

Body (JSON):

Field Type Required Description
email string Yes User email
password string Yes Account password
device_name string Yes Device label (stored with the token; e.g. iPhone 16, Pixel 9)

Success (200):

{
  "access_token": "1|…",
  "token_type": "Bearer",
  "user": {
    "id": 1,
    "name": "Jane",
    "email": "jane@example.com",
    "role": "user",
    "tenant_id": 2,
    "tenant": { "id": 2, "name": "Agency", "slug": "agency" }
  }
}

Errors: 422 validation (wrong password, inactive account, etc.).

Rate limit: 10 requests per minute per IP (by default for this route).

Current user (optional)

Method Path Auth
GET /api/v1/auth/user Bearer

Returns profile fields including vacation_pool_balance (string decimal).

Revoke current token (logout on device)

Method Path Auth
POST /api/v1/auth/revoke Bearer

Success (200): { "ok": true }


Tenant / branding context

The backend must know which tenant (organization / white-label) the request applies to, so incentive issuer settings and optional destination card images resolve correctly.

Ways to pass tenant (same as other public APIs, e.g. hotel search):

  1. Query or JSON body: tenant_id (integer, tenants.id)
  2. Query or body: tenant — id, slug, or domain string
  3. Header: X-Tenant — same as tenant (id, slug, or domain)
  4. If the app calls the tenant’s own domain and that domain is stored on tenants.domain, the host is used.
  5. If the user is signed in, tenant_id on the user is the default for non–super-admins.

Rule for normal users (not super admin): they can only redeem for their own user.tenant_id. If the resolved tenant (from X-Tenant / tenant_id) does not match, the API responds 403.

Super admin: can redeem under the tenant resolved from the request (or their own tenant_id as fallback).


Endpoints

1) List vacation destinations (public)

Method Path Auth
GET /api/v1/deals/incentives/destinations No

Query parameters:

Param Type Required Description
country string Yes ISO 3166-1 alpha-2, e.g. US
tenant_id int No If set, optional per-destination image_url may be returned from tenant marketing settings

Success (200):

{
  "data": [
    { "id": "123", "name": "Orlando … - 4 Days / 3 Nights", "image_url": "https://…" }
  ],
  "meta": {
    "source": "live",
    "master_configured": true,
    "issuer_auth_configured": true
  }
}
  • data[].id is the destination_id to send when redeeming.
  • meta.source indicates whether the list came from a live provider fetch, static fallback, etc.

Errors: 422 if country missing or invalid.

Legacy (unversioned) alias: GET /api/deals/incentives/destinations (same handler).


2) Issue / redeem vacation (protected)

Method Path Auth
POST /api/v1/deals/incentives/issue-vacation Bearer

Body (JSON):

Field Type Required Description
destination_id string Yes From GET …/destinationsdata[].id
full_name string Yes Traveler / recipient name
email string Yes Contact email
country string No 2-letter country for validation; default US
phone string No Phone
message string No Short message to issuer
tenant_id int No See “Tenant / branding context”

Success (200):

{
  "ok": true,
  "transaction_id": 42,
  "status": "sent",
  "http_status": 200,
  "error": null
}
  • ok is true only when the incentive issuer accepted the redeem.

Domain errors (200/422 with ok: false): destination not allowed for country, issuer misconfiguration, remote validation, etc. Check error and status (failed, sent, …).

HTTP: 401 if not authenticated, 403 if tenant mismatch (non–super-admin), 422 validation.

Legacy (unversioned) alias: POST /api/deals/incentives/issue-vacation (also requires auth:sanctum and Accept: application/json for API clients).

Web note: the browser may use POST /deals/incentives/issue-vacation with session auth (not necessarily Sanctum). Mobile should use the /api/v1/... path with Bearer tokens.


3) Vacation pool (protected)

Method Path Auth
GET /api/v1/deals/incentives/vacation-pool Bearer

Success (200):

{
  "data": {
    "vacation_pool_balance": "150.00",
    "entries": [
      {
        "id": 9,
        "amount": "150.00",
        "currency": "USD",
        "source": "pos_sale",
        "description": "POS sale #1001",
        "created_at": "2026-04-29T12:00:00+00:00"
      }
    ]
  }
}

vacation_pool_balance is a running total; entries are recent ledger lines (e.g. POS credits). Redeeming a vacation is recorded separately in issuer transaction logs (backend); pool display is for credits from sales and similar sources.


Server-side implementation map (for maintainers)

Concern Location
Destination list + images App\Http\Controllers\Api\MarketingboostDealsController
Redeem (issue) App\Http\Controllers\Api\MarketingboostIssueController + MarketingboostIssueEngine
Mobile token + user App\Http\Controllers\Api\MobileAuthController
Vacation pool JSON App\Http\Controllers\Api\VacationIncentiveController
Tenant resolution (API) App\Http\Controllers\Concerns\ResolvesApiTenant (aligned with availability/booking)
User model tokens Laravel\Sanctum\HasApiTokens on App\Models\User
Token storage personal_access_tokens (Sanctum migration)

Changelog (internal)

  • 2026-04-29: Sanctum for mobile, /api/v1/... routes, vacation-pool read, tenant resolution on redeem without browser session, config/auth.php sanctum guard with users provider.

Related docs in repo

  • docs/tenancy.md — tenant model and resolution patterns where relevant.

If you add OpenAPI/Swagger later, this file can be migrated to a openapi.yaml and kept in sync with the same route names.