Reference index

API Reference

Real endpoints, straight from the OpenAPI contracts in the API repository: nothing here is made up. BFF cookie session with Keycloak SSO, the user profile and the countries microservice.

Overview

The API's cross-cutting contract: servers, keys and languages.

Every call carries X-PUBLIC-KEY, the public key identifying the platform. Authenticated routes use the session cookie the login returns, and the ones that change something echo the XSRF-TOKEN cookie in the X-XSRF-TOKEN header; the login also talks to Keycloak, and the jwt block may come back null without invalidating the session. Accept-Language (pt-BR, en, es, gn) translates names and messages.

Servers

https://echosistema.live   # production
https://echosistema.dev    # QA / sandbox

Authenticate user

POST/api/v1/authBasic (email:password)

Authenticates with HTTP Basic credentials. On success the session is delivered as an HttpOnly cookie (`echosistema_bff_session`) alongside the readable CSRF cookie (`XSRF-TOKEN`): the response's `token` field is always an empty string and carries no credential. It also attempts an SSO JWT from Keycloak, returned in `jwt` — a `null` there does not mean the login failed. Pass `?with_projects=true` to include the accessible projects.

Headers

  • X-PUBLIC-KEYstring (uuid)required

    Public key identifying the platform.

  • Accept-Languagestring

    Response language: pt-BR, en, es or gn.

Query

  • with_projectsboolean

    When true, includes data.user.accessible_projects in the response.

Body

  • devicestringrequired

    Name of the device labelling the session in the account's list of connected devices.

  • flash_tokenboolean

    When true, returns a 60-second, single-use, IP-bound flash token for cross-frontend handoff via POST /api/v1/auth/flash-token.

Responses

  • 200

    Authenticated; the cookie's session is always valid, the jwt may be null.

  • 401

    Invalid credentials or missing/wrong public key.

  • 422

    Validation error in fields or parameters.

  • 500

    Internal error.

Request

curl -X POST https://echosistema.live/api/v1/auth \
  -u "sample.user@domain.com:secret123" \
  -H "X-PUBLIC-KEY: 33333333-3333-3333-3333-333333333333" \
  -H "Accept-Language: pt-BR" \
  -H "Content-Type: application/json" \
  -c cookies.txt \
  -d '{ "device": "web-browser" }'

Response 200

{
  "message": "User authenticated successfully!",
  "token": "",
  "data": {
    "user": {
      "uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "echo_uuid": "e1c1h1o1a1b2c3d4e5f6789012345678901234",
      "name": "Sample User",
      "email": "sample.user@domain.com",
      "avatar": { "url": "https://example.com/avatar.png", "usage": "avatar" },
      "language": "en",
      "currency": "USD",
      "roles": [
        {
          "id": 1,
          "platform": {
            "uuid": "22222222-2222-2222-2222-222222222222",
            "name": "Sample Platform",
            "public_key": "33333333-3333-3333-3333-333333333333"
          },
          "name": "guest",
          "localized_name": "Guest",
          "permissions": [ { "subject": "complaint", "action": "store" } ]
        }
      ],
      "company_roles": [
        {
          "id": 3,
          "platform": {
            "uuid": "22222222-2222-2222-2222-222222222222",
            "name": "Sample Platform",
            "public_key": "33333333-3333-3333-3333-333333333333"
          },
          "company": {
            "id": "64a1b2c3d4e5f6a7b8c9d0e1",
            "uuid": "44444444-4444-4444-4444-444444444444",
            "name": "Sample Company"
          },
          "name": "manager",
          "localized_name": "Manager",
          "permissions": [
            { "subject": "company", "action": "view" },
            { "subject": "company", "action": "update" }
          ]
        }
      ],
      "is_backoffice": false,
      "is_service_provider": false
    }
  },
  "jwt": {
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.example",
    "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.refresh",
    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.idtoken",
    "token_type": "Bearer",
    "expires_in": 300,
    "refresh_expires_in": 1800,
    "scope": "openid profile email",
    "issuer": "https://sso.echosistema.live/realms/echosistema",
    "subject": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "provider": { "driver": "keycloak", "name": "Keycloak Default", "kind": "oidc" }
  },
  "visitor_ip": "203.0.113.42"
}
Try endpoint

Register user

POST/api/v1/auth/registerPublic

Creates the user on the X-PUBLIC-KEY's platform and projects the identity into Keycloak. On realestate platforms the agent, professional and customer flags decide the role, in that order of priority; with no flag the user comes in as guest, and it is one role per platform. The session arrives as a cookie and the jwt block comes back as in the login.

Headers

  • X-PUBLIC-KEYstring (uuid)required

    Public key identifying the platform.

  • Accept-Languagestring

    Response language: pt-BR, en, es or gn.

Query

  • with_projectsboolean

    When true, includes data.user.accessible_projects in the response.

Body

  • namestringrequired

    User full name.

  • emailstring (email)required

    Email, unique per platform.

  • passwordstring (min 8)required

    Password, 8 characters minimum.

  • password_confirmationstringrequired

    Confirmation, must match the password.

  • devicestringrequired

    Name of the device labelling the session in the account's list of connected devices.

  • flash_tokenboolean

    When true, returns a 60-second, single-use, IP-bound flash token for cross-frontend handoff via POST /api/v1/auth/flash-token.

  • agent0 | 1

    Real-estate agent role on realestate platforms (1 = yes); priority agent, then professional, then customer.

  • professional0 | 1

    Professional role on realestate platforms (1 = yes).

  • customer0 | 1

    Customer role on realestate platforms (1 = yes).

  • intend_agency0 | 1

    Flags the intent to create or join a real-estate agency; stored in the user's raw metadata.

  • collaborator0 | 1

    Creates as collaborator (1 = yes); requires gender, birth date, nationalities, address and contacts.

  • languagestring

    User preferred language (IETF locale).

  • currencystring

    User preferred currency.

Responses

  • 200

    Registered; recently_created true and token at the root.

  • 422

    Validation error in fields or parameters.

  • 500

    Internal error.

Request

curl -X POST https://echosistema.live/api/v1/auth/register \
  -H "X-PUBLIC-KEY: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "User Example",
    "email": "user@example.com",
    "password": "secret123",
    "password_confirmation": "secret123",
    "device": "web"
  }'

Response 200

{
  "message": "User Example registered successfully.",
  "recently_created": true,
  "token": "0000|a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0",
  "data": {
    "user": {
      "uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "echo_uuid": "e1c1h1o1a1b2c3d4e5f6789012345678901234",
      "name": "User Example",
      "email": "user@example.com",
      "avatar": null,
      "language": "en",
      "currency": "USD",
      "roles": [
        {
          "id": 1,
          "platform": {
            "uuid": "22222222-2222-2222-2222-222222222222",
            "name": "Example Platform",
            "public_key": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
          },
          "name": "guest",
          "localized_name": "Guest",
          "permissions": [ { "subject": "complaint", "action": "store" } ]
        }
      ],
      "is_backoffice": false,
      "is_service_provider": false
    }
  },
  "jwt": {
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.example",
    "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.refresh",
    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.idtoken",
    "token_type": "Bearer",
    "expires_in": 300,
    "refresh_expires_in": 1800,
    "scope": "openid profile email",
    "issuer": "https://sso.echosistema.live/realms/echosistema",
    "subject": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "provider": { "driver": "keycloak", "name": "Keycloak Default", "kind": "oidc" }
  },
  "visitor_ip": "203.0.113.42"
}
Try endpoint

Log out

POST/api/v1/auth/logoutSession cookie

Revokes the BFF session (destroying the Redis mapping the cookie points at) and tells the browser to drop both cookies, the session one and the CSRF one. It attempts to end the Keycloak session on a best-effort basis, using the cached refresh_token. No request body; the `X-XSRF-TOKEN` header is required. The response is 200 even when Keycloak fails.

Headers

  • Cookiestringrequired

    The BFF session cookie `echosistema_bff_session`, set by the login. The browser attaches it on its own; with curl, use `-b`.

  • X-XSRF-TOKENstringrequired

    The `XSRF-TOKEN` cookie's value, echoed back as a header. Required on every request that changes something, whenever a session cookie is present.

Responses

  • 200

    Token revoked, best-effort; always 200.

  • 401

    No valid session: cookie missing, expired or revoked.

  • 500

    Internal error.

Request

curl -X POST https://echosistema.live/api/v1/auth/logout \
  -b cookies.txt \
  -H "X-XSRF-TOKEN: a1b2c3d4e5f6"

Response 200

{
  "message": "Goodbye, Sample User!"
}
Try endpoint

Keep session alive

GET/api/v1/auth/keep-aliveSession cookie

Extends the BFF cookie's session and attempts to refresh the Keycloak JWT with the refresh_token held in Redis. No request body. Session validity never depends on Keycloak: a failure there comes back with `jwt: null` and a `warning`, and the session stays extended.

Headers

  • Cookiestringrequired

    The BFF session cookie `echosistema_bff_session`, set by the login. The browser attaches it on its own; with curl, use `-b`.

Responses

  • 200

    Session extended; jwt refreshed, null with warning, or absent.

  • 401

    No valid session: cookie missing, expired or revoked.

  • 500

    Internal error.

Request

curl https://echosistema.live/api/v1/auth/keep-alive \
  -b cookies.txt

Response 200

{
  "message": "Session extended, Sample User.",
  "jwt": {
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.newtoken",
    "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.newrefresh",
    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.newidtoken",
    "token_type": "Bearer",
    "expires_in": 300,
    "refresh_expires_in": 1800,
    "scope": "openid profile email",
    "issuer": "https://sso.echosistema.live/realms/echosistema",
    "subject": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "provider": { "driver": "keycloak", "name": "Keycloak Default", "kind": "oidc" }
  },
  "visitor_ip": "203.0.113.42"
}
Try endpoint

Effective role and permissions

GET/api/v1/auth/permissionsSession cookie

The SPA's canonical authorization source, since the login stopped sending `permissions`. Returns the user's role on the current platform (resolved from `X-PUBLIC-KEY`) plus the effective permissions in two equivalent shapes: `permissions` as `action.subject` strings and `permissions_formatted` as pairs. The set merges the role's own permissions (approved memberships only) with those granted directly to the user.

Headers

  • Cookiestringrequired

    The BFF session cookie `echosistema_bff_session`, set by the login. The browser attaches it on its own; with curl, use `-b`.

  • X-PUBLIC-KEYstring (uuid)required

    Public key identifying the platform.

  • Accept-Languagestring

    Response language: pt-BR, en, es or gn.

Responses

  • 200

    The user's effective role and permissions on the current platform.

  • 401

    No valid session: cookie missing, expired or revoked.

  • 500

    Internal error.

Request

curl https://echosistema.live/api/v1/auth/permissions \
  -b cookies.txt \
  -H "X-PUBLIC-KEY: 33333333-3333-3333-3333-333333333333"

Response 200

{
  "success": true,
  "roles": [
    {
      "id": 2,
      "name": "administrator",
      "localized_name": "Administrador",
      "platform": {
        "uuid": "8f14e45f-ceea-4b8f-8c0e-5a4a1b3d1a2c",
        "name": "EchoSistema",
        "public_key": "33333333-3333-3333-3333-333333333333"
      }
    }
  ],
  "permissions": ["destroy.schedule", "index.all", "index.schedule", "show.all"],
  "permissions_formatted": [
    { "action": "destroy", "subject": "schedule" },
    { "action": "index", "subject": "all" },
    { "action": "index", "subject": "schedule" },
    { "action": "show", "subject": "all" }
  ]
}
Try endpoint

User profile

GET/api/v1/me/profileBearer (SSO JWT)

Returns the authenticated user's complete profile in data: identity, images in the unified card shape (avatar, banner and profile), roles with permissions, contacts, addresses, nationalities, biography, platform and affiliate.

Headers

  • Authorizationstringrequired

    Keycloak's SSO JWT, for callers outside the browser that hold a token instead of a session cookie.

  • X-PUBLIC-KEYstring (uuid)required

    Public key identifying the platform.

  • Accept-Languagestring

    Response language: pt-BR, en, es or gn.

Responses

  • 200

    Complete profile in data.

  • 401

    No valid session: cookie missing, expired or revoked.

  • 403

    Insufficient permissions.

  • 404

    User not found.

  • 500

    Internal error.

Request

curl https://echosistema.live/api/v1/me/profile \
  -H "Authorization: Bearer 1|a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0" \
  -H "X-PUBLIC-KEY: 33333333-3333-3333-3333-333333333333" \
  -H "Accept-Language: pt-BR"

Response 200

{
  "data": {
    "uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "echo_uuid": "e1c1h1o1a1b2c3d4e5f6789012345678901234",
    "name": "Sample User",
    "email": "sample.user@domain.com",
    "email_verified_at": "2026-01-15T10:30:00.000000Z",
    "slug": "sample-user",
    "avatar": {
      "unique_id": null,
      "uuid": null,
      "url": "https://storage.echosistema.live/live/common/images/default-avatar.webp",
      "usage": "avatar"
    },
    "banner": {
      "unique_id": null,
      "uuid": null,
      "url": "https://storage.echosistema.live/live/common/images/default-banner.webp",
      "usage": "banner"
    },
    "profile_image": {
      "unique_id": null,
      "uuid": null,
      "url": "https://storage.echosistema.live/live/common/images/default-profile.webp",
      "usage": "profile"
    },
    "age": null,
    "gender": null,
    "gender_name": null,
    "birthday": null,
    "is_banned": false,
    "is_foreign": false,
    "is_master": false,
    "language": "pt-BR",
    "currency": "BRL",
    "created_at": "2025-11-02T14:05:00.000000Z",
    "roles": [
      {
        "id": 1,
        "uuid": "11111111-1111-1111-1111-111111111111",
        "name": "guest",
        "localized_name": "Convidado",
        "permissions": ["complaint.store"]
      }
    ],
    "telephone": null,
    "contacts": [],
    "social_medias": [],
    "address": null,
    "addresses": [],
    "nationalities": [],
    "biography": null,
    "platform": {
      "id": 2,
      "uuid": "22222222-2222-2222-2222-222222222222",
      "name": "Sample Platform"
    },
    "affiliate": null,
    "identities": [],
    "raw": null
  }
}
Try endpoint

Update password

PUT/api/v1/me/passwordBearer (SSO JWT)

Changes the authenticated user's password: requires the current password, a 6-character minimum and confirmation, and the new one must be different. After the local save, the password is propagated best-effort to the identity provider and to every active IdentityProviderLink, with back-off retries; IdP failures never block the local change, and the plain-text password never reaches logs or queue payloads.

Headers

  • Authorizationstringrequired

    Keycloak's SSO JWT, for callers outside the browser that hold a token instead of a session cookie.

  • X-PUBLIC-KEYstring (uuid)required

    Public key identifying the platform.

  • Accept-Languagestring

    Response language: pt-BR, en, es or gn.

Body

  • current_passwordstring (password)required

    Current password, verified before the change.

  • passwordstring (min 6)required

    New password, 6 characters minimum and different from the current one.

  • password_confirmationstringrequired

    Confirmation, must match the password.

Responses

  • 200

    Password updated; SSO propagation continues in the background.

  • 400

    The new password equals the current one.

  • 401

    No valid session: cookie missing, expired or revoked.

  • 422

    Validation error in fields or parameters.

  • 500

    Internal error.

Request

curl -X PUT https://echosistema.live/api/v1/me/password \
  -H "Authorization: Bearer 1|a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0" \
  -H "X-PUBLIC-KEY: 33333333-3333-3333-3333-333333333333" \
  -H "Content-Type: application/json" \
  -d '{
    "current_password": "currentPassword123",
    "password": "newSecurePassword456",
    "password_confirmation": "newSecurePassword456"
  }'

Response 200

{
  "message": "Password updated successfully."
}
Try endpoint

List countries

GET/api/v1/public/countriesPublic

Paginated country list with filters by ISO code, name, capital, currency, language and timezone. Public route; minimum=true returns only the essential fields, ideal for dropdowns.

Headers

  • X-PUBLIC-KEYstring (uuid)required

    Public key identifying the platform.

  • Accept-Languagestring

    Response language: pt-BR, en, es or gn.

Query

  • codestring (2)

    ISO 3166-1 alpha-2 code, exact match.

  • namestring

    Country name, case-insensitive partial match.

  • cca3string (3)

    ISO 3166-1 alpha-3 code.

  • ccn3string (3)

    ISO 3166-1 numeric code.

  • ciocstring (3)

    International Olympic Committee code.

  • capitalstring

    Capital city name.

  • timezonestring

    Timezone in IANA format.

  • currencystring (3)

    ISO 4217 currency code.

  • languagesstring

    ISO 639-1 language code.

  • minimumboolean

    When true, returns only id, uuid, code, name and official_name.

  • statesstring

    Loads the states: IDs, names, or empty for all.

  • has_subdivisionsboolean

    Filters by subdivisions: true only countries with states, false only those exposing cities directly.

  • orderBystring

    Sort field: id, name, code, official_name or created_at.

  • pageinteger

    Pagination page.

  • per_pageinteger (1-200)

    Records per page, 1 to 200.

  • no_paginateboolean

    When true, returns everything without pagination.

Responses

  • 200

    Paginated list in data, with links and meta.

  • 422

    Validation error in fields or parameters.

  • 429

    Rate limit exceeded.

  • 500

    Internal error.

Request

curl "https://echosistema.live/api/v1/public/countries?code=BR" \
  -H "X-PUBLIC-KEY: pk_live_abc123def456" \
  -H "Accept-Language: pt-BR"

Response 200

{
  "data": [
    {
      "id": 1,
      "uuid": "32860919-8031-3f86-89e8-a71e5452bf6f",
      "code": "BR",
      "name": "Brazil",
      "official_name": "Federative Republic of Brazil",
      "has_subdivisions": true,
      "geolocation": { "latitude": -15.7942, "longitude": -47.8822 },
      "details": {
        "map": "https://goo.gl/maps/waCKk21HeeqFzkNC9",
        "flag": "🇧🇷",
        "name": "Brazil",
        "codes": { "cca3": "BRA", "ccn3": "076", "cioc": "BRA" },
        "region": "Americas",
        "borders": ["ARG", "BOL", "COL", "GUF", "GUY", "PRY", "PER", "SUR", "URY", "VEN"],
        "capital": "Brasília",
        "languages": [{ "code": "por", "name": "Portuguese" }],
        "subregion": "South America",
        "timezones": ["UTC-05:00", "UTC-04:00", "UTC-03:00", "UTC-02:00"],
        "continents": ["South America"],
        "currencies": [{ "code": "BRL", "name": "Brazilian real", "symbol": "R$" }],
        "postal_code": { "regex": "^(\\d{8})$", "format": "#####-###" },
        "coat_of_arms": {
          "png": "https://mainfacts.com/media/images/coats_of_arms/br.png",
          "svg": "https://mainfacts.com/media/images/coats_of_arms/br.svg"
        },
        "official_name": "Federative Republic of Brazil"
      }
    }
  ],
  "links": {
    "first": "http://echosistema.dev/api/v1/public/countries?page=1",
    "last": "http://echosistema.dev/api/v1/public/countries?page=1",
    "prev": null,
    "next": null
  },
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 1,
    "path": "http://echosistema.dev/api/v1/public/countries",
    "per_page": 25,
    "to": 1,
    "total": 1
  }
}
Try endpoint

Show country

GET/api/v1/public/countries/{country}Public

Full details of one country. The country parameter takes the ISO alpha-2 code (BR) or the numeric ID. The response carries states with every state when the country has subdivisions; without them, it exposes cities. images and texts eager-load the CDN and CMS relations.

Headers

  • X-PUBLIC-KEYstring (uuid)required

    Public key identifying the platform.

  • Accept-Languagestring

    Response language: pt-BR, en, es or gn.

Path

  • countrystringrequired

    Country identifier: ISO alpha-2 code (BR) or numeric ID. Verified on staging: UUID and alpha-3 code (BRA) return 500.

Query

  • minimumboolean

    When true, returns only id, uuid, code, name and official_name.

  • imagesboolean

    When true, eager-loads the images relation (usage mini_card).

  • textsboolean

    When true, eager-loads the CMS texts; content follows the title + body convention.

  • statesstring

    Loads the states: IDs, names, or empty for all.

Responses

  • 200

    Country details in data.

  • 404

    Country not found.

  • 429

    Rate limit exceeded.

  • 500

    Internal error.

Request

curl https://echosistema.live/api/v1/public/countries/BR \
  -H "X-PUBLIC-KEY: pk_live_abc123def456" \
  -H "Accept-Language: pt-BR"

Response 200

{
  "data": {
    "id": 1,
    "uuid": "32860919-8031-3f86-89e8-a71e5452bf6f",
    "code": "BR",
    "name": "Brazil",
    "official_name": "Federative Republic of Brazil",
    "has_subdivisions": true,
    "geolocation": { "latitude": -15.7942, "longitude": -47.8822 },
    "details": {
      "map": "https://goo.gl/maps/waCKk21HeeqFzkNC9",
      "flag": "🇧🇷",
      "name": "Brazil",
      "codes": { "cca3": "BRA", "ccn3": "076", "cioc": "BRA" },
      "region": "Americas",
      "borders": ["ARG", "BOL", "COL", "GUF", "GUY", "PRY", "PER", "SUR", "URY", "VEN"],
      "capital": "Brasília",
      "languages": [{ "code": "por", "name": "Portuguese" }],
      "subregion": "South America",
      "timezones": ["UTC-05:00", "UTC-04:00", "UTC-03:00", "UTC-02:00"],
      "continents": ["South America"],
      "currencies": [{ "code": "BRL", "name": "Brazilian real", "symbol": "R$" }],
      "postal_code": { "regex": "^(\\d{8})$", "format": "#####-###" },
      "coat_of_arms": {
        "png": "https://mainfacts.com/media/images/coats_of_arms/br.png",
        "svg": "https://mainfacts.com/media/images/coats_of_arms/br.svg"
      },
      "official_name": "Federative Republic of Brazil"
    },
    "states": [
      { "id": 1, "uuid": "43181d2e-7efd-3fb4-a831-f19149e0780b", "abbreviation": "AC", "name": "Acre", "region": "Norte" },
      { "id": 2, "uuid": "beee0aab-324c-3683-bd3b-18c9aeda7948", "abbreviation": "AL", "name": "Alagoas", "region": "Nordeste" },
      { "id": 3, "uuid": "11695e3e-d7f0-3b68-bef0-5a97515ade35", "abbreviation": "AP", "name": "Amapá", "region": "Norte" }
    ]
  }
}
Try endpoint

Show state

GET/api/v1/public/countries/{country}/states/{state}Public

Details of a state within a country. The state parameter takes the name, the numeric ID or the UUID; a name with accents and spaces travels URL-encoded. The response carries the nested country and the cities. The 404 also covers a state that does not belong to the given country.

Headers

  • X-PUBLIC-KEYstring (uuid)required

    Public key identifying the platform.

  • Accept-Languagestring

    Response language: pt-BR, en, es or gn.

Path

  • countrystringrequired

    Country identifier: ISO alpha-2 code (BR) or numeric ID. Verified on staging: UUID and alpha-3 code (BRA) return 500.

  • statestringrequired

    State identifier: name (São Paulo), numeric ID or UUID. Verified on staging: slug (sao-paulo) returns 500 and the abbreviation (SP) returns 404.

Query

  • imagesboolean

    When true, eager-loads the images relation (usage mini_card).

  • textsboolean

    When true, eager-loads the CMS texts; content follows the title + body convention.

Responses

  • 200

    State details in data.

  • 404

    Not found: country, state, or a state that does not belong to the country.

  • 422

    Validation error in fields or parameters.

  • 429

    Rate limit exceeded.

  • 500

    Internal error.

Request

curl "https://echosistema.live/api/v1/public/countries/BR/states/S%C3%A3o%20Paulo" \
  -H "X-PUBLIC-KEY: pk_live_abc123def456" \
  -H "Accept-Language: pt-BR"

Response 200

{
  "data": {
    "id": 25,
    "uuid": "db073d1d-ebe2-34e8-bf34-4884acdb475e",
    "country_id": 1,
    "name": "São Paulo",
    "abbreviation": "SP",
    "region": "Sudeste",
    "country": {
      "uuid": "32860919-8031-3f86-89e8-a71e5452bf6f",
      "name": "Brazil",
      "official_name": "Federative Republic of Brazil",
      "code": "BR"
    },
    "cities": [
      {
        "id": 2180,
        "uuid": "b5080cd5-9b2d-38cc-a6ef-7d6dfbfb2e74",
        "name": "São Paulo"
      }
    ]
  }
}
Try endpoint

Show city

GET/api/v1/public/countries/{country}/states/{state}/cities/{city}Public

Details of a city within a state and country, with chained ownership validation. Identifiers take the name, numeric ID or UUID; the response carries the nested country and state.

Headers

  • X-PUBLIC-KEYstring (uuid)required

    Public key identifying the platform.

  • Accept-Languagestring

    Response language: pt-BR, en, es or gn.

Path

  • countrystringrequired

    Country identifier: ISO alpha-2 code (BR) or numeric ID. Verified on staging: UUID and alpha-3 code (BRA) return 500.

  • statestringrequired

    State identifier: name (São Paulo), numeric ID or UUID. Verified on staging: slug (sao-paulo) returns 500 and the abbreviation (SP) returns 404.

  • citystringrequired

    City identifier: name (São Paulo), numeric ID or UUID.

Query

  • textsboolean

    When true, eager-loads the CMS texts; content follows the title + body convention.

Responses

  • 200

    City details in data.

  • 404

    Not found: country, state, city, or a broken link in the chain.

  • 422

    Validation error in fields or parameters.

  • 429

    Rate limit exceeded.

  • 500

    Internal error.

Request

curl "https://echosistema.dev/api/v1/public/countries/BR/states/S%C3%A3o%20Paulo/cities/S%C3%A3o%20Paulo" \
  -H "X-PUBLIC-KEY: pk_live_abc123def456" \
  -H "Accept-Language: pt-BR"

Response 200

{
  "data": {
    "id": 2180,
    "uuid": "b5080cd5-9b2d-38cc-a6ef-7d6dfbfb2e74",
    "state_id": 25,
    "country_id": 1,
    "name": "São Paulo",
    "abbreviation": null,
    "country": {
      "uuid": "32860919-8031-3f86-89e8-a71e5452bf6f",
      "name": "Brazil",
      "official_name": "Federative Republic of Brazil",
      "code": "BR"
    },
    "state": {
      "uuid": "db073d1d-ebe2-34e8-bf34-4884acdb475e",
      "name": "São Paulo",
      "abbreviation": "SP",
      "region": "Sudeste"
    }
  }
}
Try endpoint

Show city (Shared)

GET/api/v1/cities/{city}Public

The rich city record, outside the countries tree: it resolves by UUID or name and carries country, state, images and the editorial content (titles, topics and description). Verified on staging: it requires X-PUBLIC-KEY, and answers 403 without it.

Headers

  • X-PUBLIC-KEYstring (uuid)required

    Public key identifying the platform.

  • Accept-Languagestring

    Response language: pt-BR, en, es or gn.

Path

  • citystringrequired

    City identifier: UUID or name, auto-detected by resolveRouteBinding.

Query

  • languagestring

    IETF tag filtering titles, topics and description; is_default entries stay included. Without it, everything comes back.

Responses

  • 200

    City record in data, with the editorial content already filtered.

  • 403

    Missing or invalid public key.

  • 404

    Not found: country, state, city, or a broken link in the chain.

  • 500

    Internal error.

Request

curl "https://echosistema.dev/api/v1/cities/Encarnaci%C3%B3n?language=es" \
  -H "X-PUBLIC-KEY: pk_live_abc123def456"

Response 200

{
  "data": {
    "uuid": "35e51559-f130-31d0-bfb8-95b6c1caabfc",
    "name": "Encarnación",
    "abbreviation": "ENC",
    "country": {
      "uuid": "2eb81f74-aded-3702-b132-a7f1ce4bdf05",
      "code": "PY",
      "name": "Paraguay"
    },
    "state": {
      "uuid": "c5f7a378-0994-319b-8620-809ce6955557",
      "name": "Itapuá",
      "abb": "IT"
    },
    "images": [
      {
        "usage": "card",
        "url": "https://storage.echosistema.dev/staging/platform/echosistema/images/card/5a1f2e4d-3180-3d3b-9d60-5401e538ce3d.webp",
        "unique_id": "a796787b"
      }
    ],
    "titles": [
      {
        "index": 1,
        "uuid": "35e51559-f130-31d0-bfb8-95b6c1caabfc",
        "content": "Gestión de Propiedades",
        "language": "es",
        "is_default": true,
        "usage": "city_info",
        "details": "Encarnación experimenta un crecimiento inmobiliario acelerado…"
      }
    ],
    "topics": [
      {
        "usage": "cost_of_living",
        "language": "es",
        "is_default": true,
        "title": "Custo de vida",
        "body": "<p>Vivir en Encarnación resulta más accesible que en Asunción…</p>",
        "icon": "ri-money-dollar-circle-line"
      }
    ],
    "description": [
      {
        "usage": "general_description",
        "language": "es",
        "is_default": true,
        "title": null,
        "body": "<p>Encarnación, conocida como La Perla del Sur, es la capital…</p>"
      }
    ]
  }
}
Try endpoint