Social
Gestiona marcas, conecta cuentas sociales y publica o programa publicaciones en Facebook, Instagram, X, LinkedIn y Pinterest mediante client.social.
Todos los métodos de Social se encuentran en client.social, agrupados en cuatro espacios de nombres y una llamada de nivel superior:
IDs, plataformas y estados
Los IDs de marca, publicación y conexión son cadenas UUID sin codificar. A diferencia de los IDs de ubicación, nunca se codifican en Base64, y el SDK no los transforma.
Las plataformas son los valores de enumeración en mayúsculas FACEBOOK, INSTAGRAM, TWITTER (que corresponde a X), LINKEDIN y PINTEREST. Los estados de publicación son DRAFT, PENDING, SCHEDULED, PUBLISHED, FAILED, ARCHIVED y REJECTED; los estados por canal son SCHEDULED, SUCCESS, ERROR y ARCHIVED.
Cada operación de escritura devuelve un indicador success
Las operaciones de escritura de Social notifican los errores de validación dentro de una respuesta 200, como success: false con el motivo en error. El SDK lanza excepciones ante errores de transporte y respuestas de error que reconoce, pero conviene que compruebes success por tu cuenta:
result = client.social.brands.create(profile_name="Jenny Home", timezone=tz)if not result.success: raise RuntimeError(result.error.message)La publicación es asíncrona
action="PUBLISH" acepta la publicación y devuelve su id. Consulta social.posts.retrieve() periódicamente y lee connectedChannels[] para obtener status, liveLink y error por canal; una publicación puede completarse en una plataforma y fallar en otra en la misma llamada.
social.brands.create
Crea una marca. Solo profile_name y timezone son obligatorios.
client.social.brands.create( *, profile_name: str, timezone: dict, business_intent: str | None = None, categories: list[str] | None = None, site_url: str | None = None, logo: str | None = None, country_iso: str | None = None, bio: str | None = None, brand_hashtags: list[str] | None = None, competitor_hashtags: list[str] | None = None, content_preferred_language: str | None = None,) -> APIObjectresult = client.social.brands.create( profile_name="Jenny Home", timezone={ "label": "(GMT-05:00) Eastern Time", "tzCode": "America/New_York", "name": "Eastern Standard Time", "utc": "-05:00", }, business_intent="A family-run home furnishings store selling handmade furniture.", categories=["Furniture Store"], site_url="https://jennyhome.example",)brand_id = result.socialProfile.id # a plain UUID stringLos planes de API no limitan el número de marcas, por lo que esta operación nunca falla por alcanzar un límite. Lo que se contabiliza son las conexiones: comprueba social.limits() antes de generar un enlace de conexión, no antes de crear una marca.
social.brands.list
Lista las marcas con paginación por desplazamiento. statuses es obligatorio dentro del filtro cuando envías uno.
client.social.brands.list( *, statuses: list[str] | None = None, profile_name: str | None = None, page: int | None = None, size: int | None = None,) -> APIObjectresult = client.social.brands.list(page=1, size=25)for brand in result.profiles: print(brand.id, brand.profileName, brand.connectedChannelCount)print(result.pageInfo.total, result.pageInfo.hasNextPage)social.brands.retrieve
Obtén una marca por su UUID.
client.social.brands.retrieve(brand_id: str) -> APIObjectbrand = client.social.brands.retrieve("6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902")print(brand.profileName, brand.timezone.tzCode)social.brands.update
Actualiza una marca. Solo profile_id es obligatorio; envía únicamente los campos que vas a cambiar.
client.social.brands.update( profile_id: str, *, profile_name: str | None = None, timezone: dict | None = None, business_intent: str | None = None, categories: list[str] | None = None, site_url: str | None = None, logo: str | None = None, country_iso: str | None = None, bio: str | None = None, brand_hashtags: list[str] | None = None, competitor_hashtags: list[str] | None = None, content_preferred_language: str | None = None,) -> APIObjectcategories, brand_hashtags y competitor_hashtags sustituyen la lista almacenada cuando se envían; pasar [] la vacía.
client.social.brands.update( "6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902", profile_name="Jenny Home & Co.",)social.brands.archive
Archiva una marca y sus conexiones. La marca debe tener al menos 90 días de antigüedad.
client.social.brands.archive(social_profile_id: str) -> APIObjectresult = client.social.brands.archive("6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902")print(result.status) # ARCHIVED or TENURE_NOT_METSi una marca tiene menos de 90 días de antigüedad, se devuelven success: False y status: "TENURE_NOT_MET" y no se realiza ningún cambio. Una vez cumplida la antigüedad exigida, el archivado es inmediato: la marca y todas sus conexiones vinculadas se archivan en la misma llamada y dejan de publicar de inmediato, pero sus plazas de conexión siguen ocupadas hasta el final del ciclo de facturación, exactamente igual que con una desconexión manual.
social.connections.link
Genera una URL alojada de corta duración que guía al usuario final para conectar una plataforma a una marca. Redirige al usuario a url.
client.social.connections.link( brand_id: str, *, channel: str, redirect_url: str, error_url: str | None = None, state: str | None = None,) -> APIObjectlink = client.social.connections.link( "6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902", channel="INSTAGRAM", redirect_url="https://app.example.com/social/connected", error_url="https://app.example.com/social/connect-failed", state="sess_9f2c1e64",)print(link.url, link.expiresIn)El usuario vuelve a redirect_url con status, brandId, platform, tu state y, si la operación se completa correctamente, connectedAccountId añadidos. La conexión se crea unos instantes después, así que consulta social.connections.list() periódicamente durante unos segundos en lugar de interpretar la primera lectura vacía como un fallo. Instagram requiere una cuenta de empresa o de creador vinculada a una página de Facebook.
social.connections.list
Lista las cuentas sociales vinculadas a una marca.
client.social.connections.list(brand_id: str) -> APIObjectresult = client.social.connections.list("6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902")for channel in result.socialConnected: print(channel.id, channel.platform, channel.displayName)print(result.channelCount)channel.id es el UUID de conexión que requieren todas las demás llamadas; referenceId es el identificador de cuenta propio de la plataforma y nunca se acepta como entrada.
social.connections.disconnect
Elimina una conexión. Es irreversible: restaurarla requiere un nuevo social.connections.link().
client.social.connections.disconnect(social_profile_connected_channel_id: str) -> APIObjectclient.social.connections.disconnect("b81d5b3c-4a90-4f6a-9c11-71e0dd2fa4a7")Las publicaciones programadas para el canal no se cancelan; fallan en el momento de publicarse con SY95045. Cancélalas primero con social.posts.cancel().
social.posts.create
Crea una publicación para una marca en sus canales conectados.
client.social.posts.create( *, social_profile_id: str, name: str, platforms: list[str], content: str, action: str, media_urls: list[str] | None = None, video_urls: list[str] | None = None, link: str | None = None, scheduled_at: str | None = None, schedule_date: str | None = None, schedule_time: str | None = None, connected_channel_ids: list[str] | None = None, client_reference: str | None = None,) -> APIObjectaction="SCHEDULE" requiere exactamente una forma de programación: scheduled_at o schedule_date + schedule_time. Si envías ambas, la solicitud se rechaza con SY95046.
result = client.social.posts.create( social_profile_id="6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902", name="Autumn collection launch", platforms=["INSTAGRAM", "FACEBOOK"], content="Our autumn collection lands today. Solid oak, hand-finished.", media_urls=["https://cdn.example.com/social/autumn.jpg"], action="SCHEDULE", schedule_date="2026-10-02", schedule_time="09:30",)print(result.success, result.socialPostId)social.posts.retrieve
Obtén una publicación con su estado de publicación por canal. Consulta este método periódicamente después de crear una publicación.
client.social.posts.retrieve(post_id: str) -> APIObjectpost = client.social.posts.retrieve("c47a1e58-2b93-4f10-a6d7-58e0c9b12345")print(post.status)for channel in post.connectedChannels: print(channel.platform, channel.status, channel.liveLink, channel.error)social.posts.list
Lista las publicaciones de una marca, con paginación por desplazamiento y filtros.
client.social.posts.list( brand_id: str, *, filters: dict | None = None, page: int | None = None, size: int | None = None, fetch_post_content: bool | None = None,) -> APIObjectfilters acepta name, platforms, status, start_date, end_date, social_connected_channel_id, approval_state, view_mode y filter_by_user.
result = client.social.posts.list( "6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902", filters={"status": ["SCHEDULED"], "startDate": "2026-10-01", "endDate": "2026-10-31"}, page=1, size=50,)for post in result.socialPosts: print(post.socialPostId, post.name, post.status)print(result.pageInfo.total)social.posts.cancel
Cancela una publicación programada o en borrador para que nunca se publique.
client.social.posts.cancel(social_post_id: str) -> APIObjectclient.social.posts.cancel("c47a1e58-2b93-4f10-a6d7-58e0c9b12345")Las publicaciones ya publicadas no se pueden cancelar y no se eliminan de ninguna plataforma; la llamada devuelve success: False para ellas.
social.posts.insights
Interacciones y comentarios de una publicación ya publicada en un canal. Ambos campos se devuelven como cadenas JSON que contienen los datos propios de la plataforma.
client.social.posts.insights( post_id: str, *, social_connected_channel_id: str,) -> APIObjectimport json result = client.social.posts.insights( "c47a1e58-2b93-4f10-a6d7-58e0c9b12345", social_connected_channel_id="b81d5b3c-4a90-4f6a-9c11-71e0dd2fa4a7",)insights = json.loads(result.insights)comments = json.loads(result.comments)print(insights.get("impressions"), len(comments))Las claves que contienen son propias de cada plataforma y varían entre plataformas; compruébalas antes de usarlas.
social.bulk.create
Valida y añade a la cola hasta 500 publicaciones en una solicitud. Las filas pueden corresponder a marcas distintas.
client.social.bulk.create( posts: list[dict], *, name: str | None = None,) -> APIObjectCada fila acepta los mismos campos que social.posts.create, en camelCase. Si alguna fila no es válida, no se crea nada: success es False, SY95050 se devuelve en error y job.results[] identifica cada fila no válida por su index con índice basado en 0 y su clientReference.
result = client.social.bulk.create([ { "socialProfileId": "6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902", "name": "Autumn week 1", "platforms": ["INSTAGRAM", "FACEBOOK"], "content": "Week one of the autumn collection.", "mediaUrls": ["https://cdn.example.com/social/autumn-w1.jpg"], "action": "SCHEDULE", "scheduleDate": "2026-10-02", "scheduleTime": "09:30", "clientReference": "campaign-4471-slot-01", },])if not result.success: for row in result.job.results: print(row.index, row.clientReference, row.errors)else: job_id = result.job.idsocial.bulk.retrieve
Consulta periódicamente una tarea por lotes hasta que alcance un estado final.
client.social.bulk.retrieve(bulk_job_id: str) -> APIObjectjob = client.social.bulk.retrieve("9b3f18d0-7a26-4c51-8e94-1f0d5c6b7a82")print(job.status, job.processedCount, "/", job.totalCount)for row in job.results: print(row.clientReference, row.status, row.socialPostId)status es QUEUED, PROCESSING, COMPLETED, COMPLETED_WITH_ERRORS o FAILED. Que una fila alcance CREATED significa que la publicación existe, no que se haya publicado: pasa socialPostId a social.posts.retrieve() para obtener el resultado por canal.
social.limits
Límite de conexiones y uso actual, en una llamada.
client.social.limits() -> APIObjectlimits = client.social.limits()print(limits.maxConnections, limits.usage.connections) # pool vs usedprint(limits.brands) # None — brands are unlimitedprint(limits.usage.brands) # brands that exist, uncappedLas conexiones forman un cupo compartido por toda la cuenta —20 en Social Launch, 125 en Social Growth y 5 adicionales por cada paquete de conexiones de $25/mes—, no una asignación por marca. Compruébalo antes de generar un enlace de conexión para poder mostrar una opción de ampliación del plan en lugar de un SY95042. limits.brands es None en todos los planes de API.
Consulta también
- Planes y complementos: niveles, precios de los complementos, el grupo de conexiones y la regla de permanencia de 90 días
- Referencia de Social REST: los endpoints subyacentes que encapsulan estos métodos
- Publicaciones: el producto por ubicación, una suscripción diferente
- Gestión de errores: excepciones tipadas y el indicador
success