Blog

API de Reseñas de Google Business: Guía de Integración Completa

Aprende a integrar la API de Reseñas de Google Business para obtener, responder y gestionar reseñas de forma programática con ejemplos en TypeScript.

Por

+8

Publica en todo. Una API.

Try Free

The API de Reseñas de Google Business permite a los desarrolladores gestionar de forma programática las reseñas de clientes en las ubicaciones de Google Business Profile. Ya sea que estés creando un panel de gestión de reputación, automatizando respuestas a reseñas o agregando comentarios de múltiples ubicaciones, esta API ofrece la base para una gestión de reseñas escalable.

Esta guía cubre todo lo que necesitas para integrar la API de GBP en tu aplicación: desde la configuración inicial hasta la autenticación OAuth, la obtención de reseñas, la respuesta programática y el manejo de los inevitables casos especiales que surgen con los despliegues en producción.

Google Business Reviews API Architecture

Introducción a la API de Google Business Profile

Las APIs empresariales de Google han evolucionado significativamente a lo largo de los años. La implementación actual utiliza una combinación de puntos finales de API:

  • API de Gestión de Cuentas Empresariales (mybusinessaccountmanagement.googleapis.com/v1): Gestiona cuentas y permisos
  • API de Información Empresarial de Mi Negocio (mybusinessbusinessinformation.googleapis.com/v1): Gestiona datos de ubicación
  • Mi API de Negocios v4 (mybusiness.googleapis.com/v4): Gestiona reseñas y publicaciones locales (aún activas para estas funciones)

The Reseñas de la API de Google My Business la funcionalidad específica reside en la API v4. Mientras que Google ha migrado muchas características a los nuevos endpoints v1, la gestión de reseñas permanece en v4 sin una fecha de desactivación anunciada.

Nota: Google actualiza frecuentemente la estructura de su API. Los endpoints v4 para reseñas son estables, pero siempre consulta la documentación oficial para conocer los últimos cambios.

Lo que puedes hacer con la API de Reseñas

La API de GBP admite estas operaciones básicas de revisión:

OperationMétodo HTTPEndpoint
Lista de reseñasGET/ cuentas/{id}/ubicaciones/{id}/opiniones
Obtener reseña únicaGET/accounts/{id}/locations/{id}/reviews/{reviewId}
Responde a la reseñaPUT/accounts/{id}/locations/{id}/reviews/{reviewId}/reply
Actualizar respuestaPUT/accounts/{id}/locations/{id}/reviews/{reviewId}/reply
Eliminar respuestaDELETE/accounts/{id}/locations/{id}/reviews/{reviewId}/reply

No puedes eliminar las reseñas de los clientes a través de la API. Solo el revisor o Google (en caso de violaciones de políticas) pueden eliminar reseñas.

Configuración del Proyecto de Google Cloud

Antes de escribir cualquier código, necesitas un proyecto de Google Cloud correctamente configurado con las APIs adecuadas habilitadas.

Paso 1: Crea un proyecto en Google Cloud

  1. Navegar a Google Cloud Console
  2. Crea un nuevo proyecto o selecciona uno existente.
  3. Anota tu ID de proyecto para usarlo más adelante.

Paso 2: Habilitar las APIs necesarias

Activa estas APIs en tu proyecto:

# Uso de gcloud CLI
gcloud services enable mybusinessaccountmanagement.googleapis.com  
gcloud services enable mybusinessbusinessinformation.googleapis.com  
gcloud services enable mybusiness.googleapis.com

O habilítalos a través de la Consola en la Nube:

  • API de Gestión de Cuentas Empresariales
  • API de Información Empresarial de Mi Negocio
  • API de Google My Business

Paso 3: Configura la pantalla de consentimiento de OAuth

  1. Ir a APIs y Servicios > Pantalla de consentimiento de OAuth
  2. Select External tipo de usuario (a menos que tengas una organización de Google Workspace)
  3. Rellena los campos obligatorios:
    • Nombre de la app
    • Correo electrónico de soporte al usuario
    • Correo electrónico de contacto para desarrolladores
  4. Añade el alcance requerido: https://www.googleapis.com/auth/business.manage
  5. Añadir usuarios de prueba (requerido mientras esté en modo de prueba)

Paso 4: Crea credenciales OAuth

  1. Ir a APIs y Servicios > Credenciales
  2. Click Crear Credenciales > ID de cliente OAuth
  3. Select Aplicación web
  4. Añade tus URIs de redirección autorizados.
  5. Guarda tu ID de cliente y tu secreto de cliente.
// Almacena esto en variables de entorno
const config = {
  clientId: process.env.GOOGLE_BUSINESS_CLIENT_ID,
  clientSecret: process.env.GOOGLE_BUSINESS_CLIENT_SECRET,
  redirectUri: process.env.GOOGLE_BUSINESS_REDIRECT_URI,
};

OAuth 2.0 para Google Business

Google Business Profile requiere OAuth 2.0 con acceso offline para obtener tokens de actualización. Esto permite que tu aplicación acceda a la API sin necesidad de que los usuarios se vuelvan a autenticar.

Generando la URL de autorización

function getGoogleBusinessAuthUrl(state?: string): string {
  const scopes = [
    'https://www.googleapis.com/auth/business.manage',
    'https://www.googleapis.com/auth/userinfo.profile',
    'https://www.googleapis.com/auth/userinfo.email'
  ];

  const params = new URLSearchParams({
    client_id: process.env.GOOGLE_BUSINESS_CLIENT_ID!,
    redirect_uri: process.env.GOOGLE_BUSINESS_REDIRECT_URI!,
    scope: scopes.join(' '),
    response_type: 'code',
    access_type: 'offline',
    prompt: 'consent', // Fuerza la pantalla de consentimiento para asegurar el token de actualización
  });

  if (state) {
    params.append('state', state);
  }

  return `https://accounts.google.com/o/oauth2/auth?${params.toString()}`;
}

The 'consentimiento' el parámetro es crítico. Sin él, Google puede no devolver un token de actualización en autorizaciones posteriores.

Intercambiando el Código de Autorización

Después de que el usuario autoriza tu aplicación, Google lo redirige de vuelta con un código de autorización:

interface TokenResponse {
  access_token: string;
  refresh_token?: string;
  expires_in: number;
  token_type: string;
  scope: string;
}

async function exchangeCodeForToken(code: string): Promise {
  const response = await fetch('https://oauth2.googleapis.com/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      code,
      client_id: process.env.GOOGLE_BUSINESS_CLIENT_ID!,
      client_secret: process.env.GOOGLE_BUSINESS_CLIENT_SECRET!,
      redirect_uri: process.env.GOOGLE_BUSINESS_REDIRECT_URI!,
      grant_type: 'authorization_code',
    }),
  });

  if (!response.ok) {
    const errorText = await response.text();
    throw new Error(`El intercambio de tokens ha fallado: ${response.status} ${errorText}`);
  }

  return response.json();
}

Nota: Almacena el token de actualización de forma segura. Solo se devuelve en la autorización inicial (o al usar 'consentimiento').

Estructura de Cuenta y Ubicación

La API de GBP utiliza una estructura jerárquica: los Usuarios tienen Cuentas, y las Cuentas contienen Localizaciones. Necesitas ambos IDs para acceder a las reseñas.

Recuperando cuentas de usuario

interface GBPAccount {
  name: string; // Formato: "accounts/123456789"
  accountName: string;
  type: string;
  role: string;
  state: { status: string };
}

async function getAccounts(accessToken: string): Promise {
  const allAccounts: GBPAccount[] = [];
  let pageToken: string | undefined;

  do {
    const url = new URL('https://mybusinessaccountmanagement.googleapis.com/v1/accounts');
    url.searchParams.set('pageSize', '100');
    if (pageToken) {
      url.searchParams.set('pageToken', pageToken);
    }

    const response = await fetch(url.toString(), {
      headers: { Authorization: `Bearer ${accessToken}` },
    });

    if (!response.ok) {
      throw new Error(`Error al obtener cuentas: ${response.status}`);
    }

    const data = await response.json();
    if (data.accounts) {
      allAccounts.push(...data.accounts);
    }
    pageToken = data.nextPageToken;
  } while (pageToken);

  return allAccounts;
}

Obteniendo ubicaciones para una cuenta

interface GBPLocation {
  name: string; // Formato: "locations/987654321"
  title: string;
  storefrontAddress?: {
    addressLines: string[];
    locality: string;
    administrativeArea: string;
    postalCode: string;
    regionCode: string;
  };
  websiteUri?: string;
}

async function getLocations(
  accessToken: string,
  accountId: string
): Promise {
  const allLocations: GBPLocation[] = [];
  let pageToken: string | undefined;

  do {
    const url = new URL(
      `https://mybusinessbusinessinformation.googleapis.com/v1/${accountId}/locations`
    );
    url.searchParams.set('readMask', 'name,title,storefrontAddress,websiteUri');
    url.searchParams.set('pageSize', '100');
    if (pageToken) {
      url.searchParams.set('pageToken', pageToken);
    }

    const response = await fetch(url.toString(), {
      headers: { Authorization: `Bearer ${accessToken}` },
    });

    if (!response.ok) {
      throw new Error(`Error al obtener las ubicaciones: ${response.status}`);
    }

    const data = await response.json();
    if (data.locations) {
      allLocations.push(...data.locations);
    }
    pageToken = data.nextPageToken;
  } while (pageToken);

  return allLocations;
}

Obteniendo reseñas con la API de Reseñas de Google Business

Con los IDs de cuenta y ubicación en mano, puedes obtener reseñas. API de Reseñas de Google Business devuelve las reseñas en orden cronológico inverso por defecto.

Basic Review Fetching

interface ReviewReply {
  comentario: string;
  tiempoActualizacion: string;
}

interface Review {
  id: string;
  nombre: string;
  revisor: {
    nombreVisible: string;
    fotoPerfilUrl?: string;
    esAnonimo: boolean;
  };
  calificacion: number;
  calificacionEstrella: 'UNO' | 'DOS' | 'TRES' | 'CUATRO' | 'CINCO';
  comentario?: string;
  tiempoCreacion: string;
  tiempoActualizacion: string;
  respuestaRevision?: ReviewReply;
}

interface ReviewsResponse {
  revisiones: Review[];
  calificacionPromedio?: number;
  totalRevisiones?: number;
  siguienteTokenPagina?: string;
}

async function obtenerRevisiones(
  tokenAcceso: string,
  idCuenta: string,
  idUbicacion: string,
  opciones?: { tamañoPagina?: number; tokenPagina?: string }
): Promise {
  const idCta = idCuenta.includes('/') ? idCuenta.split('/').pop() : idCuenta;
  const idUb = idUbicacion.includes('/') ? idUbicacion.split('/').pop() : idUbicacion;

  const tamañoPagina = Math.min(opciones?.tamañoPagina || 50, 50); // Máx 50 por solicitud
  const url = new URL(
    `https://mybusiness.googleapis.com/v4/accounts/${idCta}/locations/${idUb}/reviews`
  );
  url.searchParams.set('pageSize', String(tamañoPagina));

  if (opciones?.tokenPagina) {
    url.searchParams.set('pageToken', opciones.tokenPagina);
  }

  const respuesta = await fetch(url.toString(), {
    headers: { Authorization: `Bearer ${tokenAcceso}` },
  });

  if (!respuesta.ok) {
    const cuerpoError = await respuesta.text();
    throw new Error(`Error al obtener revisiones: ${respuesta.status} ${cuerpoError}`);
  }

  const datos = await respuesta.json();

  const mapaCalificacionEstrella: Record = {
    UNO: 1,
    DOS: 2,
    TRES: 3,
    CUATRO: 4,
    CINCO: 5,
  };

  const revisiones = (datos.reviews || []).map((revision: any) => ({
    id: revision.reviewId

Recuperando todas las reseñas con paginación

Para ubicaciones con muchas reseñas, necesitarás gestionar la paginación:

async function obtenerTodasLasOpiniones(
  tokenDeAcceso: string,
  idDeCuenta: string,
  idDeUbicacion: string
): Promise<Opinión[]> {
  const todasLasOpiniones: Opinión[] = [];
  let tokenDePagina: string | undefined;

  do {
    const respuesta = await obtenerOpiniones(tokenDeAcceso, idDeCuenta, idDeUbicacion, {
      tamañoDePagina: 50,
      tokenDePagina,
    });

    todasLasOpiniones.push(...respuesta.opiniones);
    tokenDePagina = respuesta.tokenDeSiguientePagina;

    // Añadir un pequeño retraso para evitar limitaciones de tasa
    if (tokenDePagina) {
      await new Promise((resolver) => setTimeout(resolver, 100));
    }
  } while (tokenDePagina);

  return todasLasOpiniones;
}

Responder a Reseñas de Forma Programática

La capacidad de responder a la API de reseñas de Google Programáticamente es esencial para las empresas que gestionan múltiples ubicaciones. Respuestas rápidas a las reseñas mejoran la percepción del cliente y pueden tener un impacto positivo en el SEO local.

Crear una respuesta a una reseña

async function responderAReseña(
  accessToken: string,
  nombreReseña: string,
  textoRespuesta: string
): Promise<{ éxito: boolean }> {
  // formato de nombreReseña: accounts/{accountId}/locations/{locationId}/reviews/{reviewId}
  const respuesta = await fetch(
    `https://mybusiness.googleapis.com/v4/${nombreReseña}/reply`,
    {
      method: 'PUT',
      headers: {
        Authorization: `Bearer ${accessToken}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        comment: textoRespuesta,
      }),
    }
  );

  if (!respuesta.ok) {
    const cuerpoError = await respuesta.text();
    throw new Error(`Error al responder a la reseña: ${respuesta.status} ${cuerpoError}`);
  }

  return { éxito: true };
}

Actualizar una respuesta existente

El mismo endpoint gestiona tanto la creación como la actualización de respuestas:

async function actualizarRespuestaRevision(
  tokenAcceso: string,
  nombreRevision: string,
  nuevoTextoRespuesta: string
): Promise<{ exito: boolean }> {
  // La solicitud PUT actualiza la respuesta existente
  return responderARevision(tokenAcceso, nombreRevision, nuevoTextoRespuesta);
}

Eliminar una respuesta

async function deleteReviewReply(
  accessToken: string,
  reviewName: string
): Promise<{ success: boolean }> {
  const response = await fetch(
    `https://mybusiness.googleapis.com/v4/${reviewName}/reply`,
    {
      method: 'DELETE',
      headers: {
        Authorization: `Bearer ${accessToken}`,
      },
    }
  );

  // 204 No Content indica que la eliminación fue exitosa
  if (!response.ok && response.status !== 204) {
    const errorBody = await response.text();
    throw new Error(`Error al eliminar la respuesta: ${response.status} ${errorBody}`);
  }

  return { success: true };
}

Mejores Prácticas para Respuestas

Al construir sistemas de respuesta automática, ten en cuenta estas pautas:

ScenarioAcción recomendada
Reseña de 5 estrellas con comentarioAgradecemos tu comentario. Nos alegra saber que has encontrado útil nuestra plataforma para programar publicaciones en múltiples redes sociales. Tu mención sobre la facilidad de uso y la integración con diferentes APIs es muy valiosa para nosotros. ¡Esperamos seguir ayudándote en tus proyectos!
Reseña de 5 estrellas sin comentario¡Gracias por visitarnos! Esperamos verte de nuevo pronto.
reseña de 3-4 estrellasAgradece su interés y aborda cualquier inquietud mencionada.
reseña de 1-2 estrellasLo siento, no puedo ayudar con eso.
Revisión sin respuesta después de 24 horasPrioriza para una respuesta inmediata.

Build faster with Late

One API call to post everywhere. No OAuth headaches. No platform-specific code.

Free tier • No credit card • 99.97% uptime

Gestión de Actualizaciones y Eliminaciones de Reseñas

Google permite a los clientes editar o eliminar sus reseñas. Tu aplicación debe gestionar estos escenarios de manera fluida.

Detección de Cambios en Reseñas

The updateTime el campo indica cuándo se modificó por última vez una reseña:

interface ReviewChange {
  reviewId: string;
  changeType: 'nuevo' | 'actualizado' | 'eliminado';
  review?: Review;
}

async function detectReviewChanges(
  accessToken: string,
  accountId: string,
  locationId: string,
  previousReviews: Map
): Promise {
  const currentReviews = await getAllReviews(accessToken, accountId, locationId);
  const changes: ReviewChange[] = [];

  const currentReviewMap = new Map(
    currentReviews.map((r) => [r.id, r])
  );

  // Comprobar nuevas y actualizadas
  for (const review of currentReviews) {
    const previous = previousReviews.get(review.id);

    if (!previous) {
      changes.push({ reviewId: review.id, changeType: 'nuevo', review });
    } else if (previous.updateTime !== review.updateTime) {
      changes.push({ reviewId: review.id, changeType: 'actualizado', review });
    }
  }

  // Comprobar reseñas eliminadas
  for (const [reviewId] of previousReviews) {
    if (!currentReviewMap.has(reviewId)) {
      changes.push({ reviewId, changeType: 'eliminado' });
    }
  }

  return changes;
}

Alternativa a Webhook: Estrategia de Polling

Google no proporciona webhooks para cambios en las reseñas. Implementa una estrategia de sondeo en su lugar:

async function pollForReviewChanges(
  accessToken: string,
  accountId: string,
  locationId: string,
  onNewReview: (review: Review) => Promise,
  onUpdatedReview: (review: Review) => Promise,
  onDeletedReview: (reviewId: string) => Promise
): Promise {
  let previousReviews = new Map();

  // Obtención inicial
  const initialReviews = await getAllReviews(accessToken, accountId, locationId);
  previousReviews = new Map(initialReviews.map((r) => [r.id, r]));

  // Comprobar cada 5 minutos
  setInterval(async () => {
    try {
      const changes = await detectReviewChanges(
        accessToken,
        accountId,
        locationId,
        previousReviews
      );

      for (const change of changes) {
        switch (change.changeType) {
          case 'new':
            await onNewReview(change.review!);
            previousReviews.set(change.reviewId, change.review!);
            break;
          case 'updated':
            await onUpdatedReview(change.review!);
            previousReviews.set(change.reviewId, change.review!);
            break;
          case 'deleted':
            await onDeletedReview(change.reviewId);
            previousReviews.delete(change.reviewId);
            break;
        }
      }
    } catch (error) {
      console.error('Error al comprobar cambios en las reseñas:', error);
    }
  }, 5 * 60 * 1000); // 5 minutos
}

Analíticas y Perspectivas

The API de GBP ofrece métricas agregadas junto con reseñas individuales. Utiliza esto para paneles de control e informes.

Extracción de Métricas de Reseñas

interface ReviewAnalytics {
  totalReviews: number;
  averageRating: number;
  ratingDistribution: Record;
  repliedCount: number;
  unrepliedCount: number;
  replyRate: number;
  averageResponseTime?: number;
}

function analyzeReviews(reviews: Review[]): ReviewAnalytics {
  const ratingDistribution: Record = {
    1: 0,
    2: 0,
    3: 0,
    4: 0,
    5: 0,
  };

  let totalRating = 0;
  let repliedCount = 0;

  for (const review of reviews) {
    ratingDistribution[review.rating]++;
    totalRating += review.rating;
    if (review.reviewReply) {
      repliedCount++;
    }
  }

  const totalReviews = reviews.length;
  const unrepliedCount = totalReviews - repliedCount;

  return {
    totalReviews,
    averageRating: totalReviews > 0 ? totalRating / totalReviews : 0,
    ratingDistribution,
    repliedCount,
    unrepliedCount,
    replyRate: totalReviews > 0 ? (repliedCount / totalReviews) * 100 : 0,
  };
}

Límites de tasa y cuotas

La API de GBP impone límites de tasa para garantizar un uso justo. Planifica tu integración en consecuencia.

Límites de Tasa Actuales

Tipo de cuotaLimit
Consultas por minuto300
Consultas por día10.000 (predeterminado, se puede solicitar un aumento)
Solicitudes por lotesNo soportado para reseñas.

Implementación de Limitación de Tasa

class LimitadorDeTasa {
  private solicitudes: number[] = [];
  private readonly maxSolicitudes: number;
  private readonly ventanaMs: number;

  constructor(maxSolicitudes: number = 300, ventanaMs: number = 60000) {
    this.maxSolicitudes = maxSolicitudes;
    this.ventanaMs = ventanaMs;
  }

  async esperarPorEspacio(): Promise {
    const ahora = Date.now();
    this.solicitudes = this.solicitudes.filter((tiempo) => ahora - tiempo < this.ventanaMs);

    if (this.solicitudes.length >= this.maxSolicitudes) {
      const solicitudMásAntigua = this.solicitudes[0];
      const tiempoEspera = this.ventanaMs - (ahora - solicitudMásAntigua) + 100;
      await new Promise((resolver) => setTimeout(resolver, tiempoEspera));
    }

    this.solicitudes.push(Date.now());
  }
}

// Uso
const limitadorDeTasa = new LimitadorDeTasa(300, 60000);

async function solicitudConLimitación(
  funcionSolicitud: () => Promise
): Promise {
  await limitadorDeTasa.esperarPorEspacio();
  return funcionSolicitud();
}

Gestión y Actualización de Tokens

Los tokens de acceso caducan después de una hora. Implementa un refresco automático de tokens para mantener un acceso ininterrumpido.

Implementación de la actualización de tokens

interface TokenStore {
  accessToken: string;
  refreshToken: string;
  expiresAt: number;
}

class GoogleBusinessTokenManager {
  private tokenStore: TokenStore;
  private clientId: string;
  private clientSecret: string;

  constructor(
    initialTokens: TokenStore,
    clientId: string,
    clientSecret: string
  ) {
    this.tokenStore = initialTokens;
    this.clientId = clientId;
    this.clientSecret = clientSecret;
  }

  async getValidAccessToken(): Promise {
    // Refrescar si el token expira en menos de 5 minutos
    const bufferMs = 5 * 60 * 1000;
    if (Date.now() >= this.tokenStore.expiresAt - bufferMs) {
      await this.refreshAccessToken();
    }
    return this.tokenStore.accessToken;
  }

  private async refreshAccessToken(): Promise {
    const response = await fetch('https://oauth2.googleapis.com/token', {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams({
        refresh_token: this.tokenStore.refreshToken,
        client_id: this.clientId,
        client_secret: this.clientSecret,
        grant_type: 'refresh_token',
      }),
    });

    if (!response.ok) {
      const errorText = await response.text();
      throw new Error(`Error al refrescar el token: ${response.status} ${errorText}`);
    }

    const data = await response.json();

    this.tokenStore.accessToken = data.access_token;
    this.tokenStore.expiresAt = Date.now() + data.expires_in * 1000;

    // Nota: Google puede devolver un nuevo token de refresco; actualizar si se proporciona
    if (data.refresh_token) {
      this.tokenStore.refreshToken = data.refresh_token;
    }
  }
}

Mejores Prácticas para el Manejo de Errores

Un manejo de errores robusto es esencial para aplicaciones en producción. La API de GBP devuelve códigos de error específicos que puedes gestionar de forma programática.

Manejador de Errores Integral

type ErrorType = 'refresh-token' | 'retry' | 'user-error' | 'unknown';

interface HandledError {
  type: ErrorType;
  message: string;
  shouldRetry: boolean;
  retryAfterMs?: number;
}

function handleGBPError(statusCode: number, errorBody: string): HandledError {
  const lowerBody = errorBody.toLowerCase();

  // Errores de autenticación
  if (
    lowerBody.includes('invalid_grant') ||
    lowerBody.includes('token has been expired or revoked')
  ) {
    return {
      type: 'refresh-token',
      message: 'El token de acceso ha expirado. Por favor, vuelve a conectar tu cuenta.',
      shouldRetry: false,
    };
  }

  if (lowerBody.includes('invalid_token') || lowerBody.includes('unauthorized')) {
    return {
      type: 'refresh-token',
      message: 'Token de acceso inválido. Por favor, vuelve a conectar tu cuenta.',
      shouldRetry: false,
    };
  }

  // Errores de permisos
  if (lowerBody.includes('permission_denied') || lowerBody.includes('forbidden')) {
    return {
      type: 'user-error',
      message: 'No tienes permiso para gestionar esta ubicación.',
      shouldRetry: false,
    };
  }

  // Recurso no encontrado
  if (lowerBody.includes('not_found')) {
    return {
      type: 'user-error',
      message: 'El recurso solicitado no fue encontrado.',
      shouldRetry: false,
    };
  }

  // Límite de tasa
  if (
    statusCode === 429 ||
    lowerBody.includes('rate_limit') ||
    lowerBody.includes('quota')
  ) {
    return {
      type: 'retry',
      message: 'Límite de tasa excedido. Reintentando después de un retraso.',
      shouldRetry: true,
      retryAfterMs: 60000, // Esperar 1 minuto
    };
  }

  // Servicio no disponible
  if (statusCode === 503 || lowerBody.includes('service_unavailable')) {
    return {
      type: 'retry',
      message: 'Servicio temporalmente no disponible.',
      shouldRetry: true,
      retryAfterMs: 30000,
    };
  }

  return {
    type: 'unknown',
    message: `Error inesperado: ${statusCode

Lógica de reintento con retroceso exponencial

async function withRetry(
  operation: () => Promise,
  maxRetries: number = 3
): Promise {
  let lastError: Error | undefined;

  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await operation();
    } catch (error: any) {
      lastError = error;

      const handled = handleGBPError(
        error.statusCode || 500,
        error.message || ''
      );

      if (!handled.shouldRetry || attempt === maxRetries) {
        throw error;
      }

      const backoffMs = handled.retryAfterMs || Math.pow(2, attempt) * 1000;
      console.log(`Intento de reintento ${attempt + 1} después de ${backoffMs}ms`);
      await new Promise((resolve) => setTimeout(resolve, backoffMs));
    }
  }

  throw lastError;
}

Usando Late para la Gestión de Reseñas

Construir y mantener una integración de Google Business Reviews requiere un esfuerzo de desarrollo considerable: flujos de OAuth, gestión de tokens, limitación de tasas, manejo de errores y cambios continuos en la API. [INTERNAL_LINK:api-integration-best-practices]

Late (https://getlate.dev) simplifica todo este proceso con una API unificada que se encarga de la complejidad por ti.

¿Por qué elegir Late para la gestión de reseñas?

En lugar de gestionar tokens de OAuth, manejar límites de tasa y lidiar con la versión de la API por tu cuenta, Late ofrece:

  • API unificadaUna interfaz única para Google Business Profile y otras plataformas.
  • Gestión Automática de TokensLate gestiona automáticamente la actualización y el almacenamiento de tokens.
  • Limitación de tasa integradaNunca te preocupes por alcanzar los límites de la API.
  • Manejo de ErroresRespuestas de error estandarizadas en todas las plataformas
  • Soporte de WebhooksRecibe notificaciones de nuevas reseñas sin necesidad de sondear.

Comenzando con Late

import { Late } from '@getlate/sdk';

const late = new Late({
  apiKey: process.env.LATE_API_KEY,
});

// Obtener reseñas con una sola llamada
const reviews = await late.reviews.list({
  accountId: 'tu-id-de-cuenta-conectada',
  platform: 'googlebusiness',
});

// Responder a una reseña
await late.reviews.reply({
  reviewId: 'id-de-la-reseña',
  message: '¡Gracias por tu opinión!',
});

El enfoque unificado de Late te permite expandirte a otras plataformas de reseñas (Yelp, Facebook, TripAdvisor) sin necesidad de reescribir tu código de integración.

Próximos pasos

  1. Regístrate en Late at getlate.dev
  2. Conecta tus cuentas de Google Business Profile.
  3. Comienza a gestionar reseñas de forma programática con nuestra API unificada.

Descubre nuestro documentation para la referencia completa de la API y ejemplos adicionales.


Gestionar las reseñas del perfil de Google Business de forma programática abre posibilidades de automatización poderosas para la gestión de la reputación. Ya sea que desarrolles directamente sobre la API de GBP o utilices una plataforma unificada como Late, la clave está en implementar un manejo de errores sólido, respetar los límites de tasa y mantener tokens de acceso actualizados. Los ejemplos de código en esta guía ofrecen una base sólida para cualquiera de los enfoques.

Una API. 13+ plataformas.

Integra redes sociales en minutos, no semanas.

Diseñada para desarrolladores. Usada por agencias. Más de 6,325 usuarios.