Social
Gestisci i brand, collega gli account social e pubblica o programma post su Facebook, Instagram, X, LinkedIn e Pinterest tramite client.social.
Tutti i metodi di Social si trovano in client.social, raggruppati in quattro namespace più una chiamata di primo livello:
ID, piattaforme e stati
Gli ID di brand, post e connessioni sono semplici stringhe UUID. A differenza degli ID delle sedi, non sono mai codificati in Base64 e l'SDK non li trasforma.
Le piattaforme sono i valori enum in maiuscolo FACEBOOK, INSTAGRAM, TWITTER (che corrisponde a X), LINKEDIN e PINTEREST. Gli stati dei post sono DRAFT, PENDING, SCHEDULED, PUBLISHED, FAILED, ARCHIVED e REJECTED; gli stati per canale sono SCHEDULED, SUCCESS, ERROR e ARCHIVED.
Ogni operazione di scrittura restituisce un flag success
Le operazioni di scrittura di Social segnalano gli errori di validazione all'interno di una risposta 200, come success: false con il motivo in error. L'SDK solleva eccezioni in caso di errori di trasporto e payload di errore che riconosce, ma è buona pratica controllare direttamente success:
result = client.social.brands.create(profile_name="Jenny Home", timezone=tz)if not result.success: raise RuntimeError(result.error.message)La pubblicazione è asincrona
action="PUBLISH" accetta il post e ne restituisce l'id. Interroga periodicamente social.posts.retrieve() e leggi connectedChannels[] per ottenere status, liveLink e error per ciascun canale; nella stessa chiamata, la pubblicazione di un post può riuscire su una piattaforma e fallire su un'altra.
social.brands.create
Crea un brand. Solo profile_name e timezone sono obbligatori.
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 stringI piani API non prevedono un limite al numero di brand, quindi questa operazione non fallisce mai per il raggiungimento di un limite. Il conteggio riguarda le connessioni: controlla social.limits() prima di generare un link di connessione, non prima di creare un brand.
social.brands.list
Elenca i brand con paginazione basata su offset. Quando invii un filtro, statuses è obbligatorio al suo interno.
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
Recupera un brand tramite il suo 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
Aggiorna un brand. Solo profile_id è obbligatorio; invia soltanto i campi che stai modificando.
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 e competitor_hashtags sostituiscono l'elenco memorizzato quando vengono inviati; passando [], lo svuoti.
client.social.brands.update( "6f2c9a41-7b0e-4d55-9a2f-3c8e1d47b902", profile_name="Jenny Home & Co.",)social.brands.archive
Archivia un brand e le sue connessioni. Il brand deve essere stato creato da almeno 90 giorni.
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_METPer un brand creato da meno di 90 giorni vengono restituiti success: False e status: "TENURE_NOT_MET" e non cambia nulla. Una volta trascorso il periodo richiesto, l'archiviazione è immediata: il brand e tutte le connessioni collegate vengono archiviati nella stessa chiamata e smettono subito di pubblicare, ma i posti occupati dalle connessioni restano riservati fino alla fine del ciclo di fatturazione, esattamente come avverrebbe con una disconnessione manuale.
social.connections.link
Genera un URL ospitato di breve durata che guida l'utente finale nel collegamento di una piattaforma a un brand. Reindirizzalo 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)L'utente torna a redirect_url con l'aggiunta di status, brandId, platform, del tuo state e, in caso di esito positivo, di connectedAccountId. La connessione viene creata poco dopo, quindi interroga periodicamente social.connections.list() per alcuni secondi invece di considerare la prima lettura vuota come un errore. Instagram richiede un account Business o Creator collegato a una Pagina Facebook.
social.connections.list
Elenca gli account social collegati a un brand.
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 è l'UUID della connessione richiesto da tutte le altre chiamate; referenceId è l'identificatore dell'account assegnato dalla piattaforma e non viene mai accettato come input.
social.connections.disconnect
Rimuovi una connessione. L'operazione è irreversibile: per ripristinarla serve un nuovo social.connections.link().
client.social.connections.disconnect(social_profile_connected_channel_id: str) -> APIObjectclient.social.connections.disconnect("b81d5b3c-4a90-4f6a-9c11-71e0dd2fa4a7")I post programmati per il canale non vengono annullati; la loro pubblicazione fallisce con SY95045. Annullali prima con social.posts.cancel().
social.posts.create
Crea un post per un brand sui suoi canali collegati.
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" richiede esattamente una modalità di programmazione: scheduled_at oppure schedule_date + schedule_time. L'invio di entrambe viene rifiutato 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
Recupera un post con lo stato di pubblicazione per ciascun canale. Dopo la creazione, esegui periodicamente questa chiamata.
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
Elenca i post di un brand, con paginazione basata su offset e filtri.
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 accetta name, platforms, status, start_date, end_date, social_connected_channel_id, approval_state, view_mode e 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
Annulla un post programmato o in bozza in modo che non venga mai pubblicato.
client.social.posts.cancel(social_post_id: str) -> APIObjectclient.social.posts.cancel("c47a1e58-2b93-4f10-a6d7-58e0c9b12345")I post già pubblicati non possono essere annullati e non vengono rimossi da nessuna piattaforma; per questi post la chiamata restituisce success: False.
social.posts.insights
Interazioni e commenti per un post pubblicato su un canale. Entrambi i campi vengono restituiti come stringhe JSON contenenti il payload della piattaforma.
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))Le chiavi al loro interno sono definite dalla piattaforma e variano da una piattaforma all'altra; leggile prevedendo controlli sui dati.
social.bulk.create
Valida e accoda fino a 500 post in una richiesta. Le righe possono riferirsi a brand diversi.
client.social.bulk.create( posts: list[dict], *, name: str | None = None,) -> APIObjectOgni riga accetta gli stessi campi di social.posts.create, in camelCase. Se anche una sola riga non è valida, non viene creato nulla: success è False, SY95050 viene restituito in error e job.results[] identifica ogni riga non valida tramite il suo index con indice a partire da 0 e il suo 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
Interroga periodicamente un processo in blocco finché non raggiunge uno stato finale.
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 è QUEUED, PROCESSING, COMPLETED, COMPLETED_WITH_ERRORS o FAILED. Quando una riga raggiunge CREATED, significa che il post esiste, non che è stato pubblicato: passa socialPostId a social.posts.retrieve() per ottenere l'esito per ciascun canale.
social.limits
Limite di connessioni e utilizzo attuale, in una chiamata.
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, uncappedLe connessioni costituiscono una quota condivisa nell'intero account — 20 con Social Launch, 125 con Social Growth, più 5 per ogni pacchetto di connessioni da $25 al mese — e non una quota per brand. Controllala prima di generare un link di connessione, così puoi mostrare un'opzione per passare a un piano superiore invece di un SY95042. limits.brands è None in tutti i piani API.
Vedi anche
- Piani e componenti aggiuntivi: livelli, prezzi dei componenti aggiuntivi, pool di connessioni e regola della permanenza di 90 giorni
- Riferimento REST per Social: gli endpoint sottostanti richiamati da questi metodi
- Post: il prodotto a livello di sede, con un abbonamento diverso
- Gestione degli errori: eccezioni tipizzate e flag
success