fix: fall back to Facebook-only when ad account can't use the page's Instagram
Meta rejects the whole ad creative with error 200/1815199 when the ad account isn't authorized (in Business Manager) to use the Instagram account linked to the chosen page. Picking a different page in the new selector doesn't help if that page's IG is also unshared. Now, when the creative fails for that specific reason, we retry without instagram_actor_id so the ad still publishes on Facebook, and the modal explains why Instagram was dropped and how to enable it. createFullCampaign gets the same fallback for free. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
dcaf7959ac
commit
a88e96adf5
2 changed files with 49 additions and 18 deletions
|
|
@ -80,6 +80,7 @@ export function AddAdModal({
|
|||
const [publishing, setPublishing] = useState(false);
|
||||
const [error, setError] = useState<FriendlyError | string | null>(null);
|
||||
const [done, setDone] = useState(false);
|
||||
const [instagramDropped, setInstagramDropped] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
|
|
@ -271,6 +272,7 @@ export function AddAdModal({
|
|||
return;
|
||||
}
|
||||
|
||||
setInstagramDropped(Boolean(data.data?.instagram_dropped));
|
||||
setDone(true);
|
||||
onCreated();
|
||||
} catch (err) {
|
||||
|
|
@ -301,6 +303,13 @@ export function AddAdModal({
|
|||
<p className="text-xs" style={{ color: 'var(--muted-fg)' }}>
|
||||
Ele foi criado como Pausado — ative-o no Ads Manager (ou na tabela) quando estiver pronto.
|
||||
</p>
|
||||
{instagramDropped && (
|
||||
<div className="text-[11px] mt-1 px-3 py-2 rounded-lg text-left" style={{ background: 'rgba(234,179,8,0.08)', border: '1px solid rgba(234,179,8,0.2)', color: '#fcd34d' }}>
|
||||
⚠️ Publicamos <strong>só no Facebook</strong>: a conta de anúncios ainda não tem permissão pra usar
|
||||
{selectedInstagramAccount ? <> a conta <strong>@{selectedInstagramAccount.username}</strong></> : ' a conta do Instagram'} desta página.
|
||||
Para ativar o Instagram, vincule a conta no Business Manager (Configurações do Negócio → Contas do Instagram → Atribuir conta de anúncios) e republique.
|
||||
</div>
|
||||
)}
|
||||
<button onClick={onClose} className="btn-primary mt-2">Fechar</button>
|
||||
</div>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -608,26 +608,30 @@ export async function addAdToAdSet(client: Client, params: AddAdToAdSetParams) {
|
|||
// the most broadly compatible across placements.
|
||||
const primaryImageHash = imageHashes[0];
|
||||
|
||||
let creative;
|
||||
if (params.is_whatsapp) {
|
||||
creative = await createWhatsappAdCreative(client, {
|
||||
// Monta o criativo com (ou sem) o Instagram. Quando a conta de anúncios não
|
||||
// tem permissão pra usar a conta de IG vinculada à página, a Meta recusa o
|
||||
// criativo inteiro (erro 200 / subcode 1815199). Nesse caso refazemos o
|
||||
// criativo só com o Facebook, em vez de barrar a publicação.
|
||||
const buildCreative = (instagramActorId?: string) => {
|
||||
if (params.is_whatsapp) {
|
||||
return createWhatsappAdCreative(client, {
|
||||
name: creativeName,
|
||||
page_id: params.page_id,
|
||||
instagram_actor_id: instagramActorId,
|
||||
image_hash: primaryImageHash,
|
||||
message: params.primary_text,
|
||||
headline: params.headline,
|
||||
description: params.description,
|
||||
link: params.link,
|
||||
whatsapp_link: params.whatsapp_link,
|
||||
whatsapp_phone_number: params.whatsapp_phone_number,
|
||||
ad_account_id: params.ad_account_id,
|
||||
});
|
||||
}
|
||||
return createAdCreative(client, {
|
||||
name: creativeName,
|
||||
page_id: params.page_id,
|
||||
instagram_actor_id: params.instagram_actor_id,
|
||||
image_hash: primaryImageHash,
|
||||
message: params.primary_text,
|
||||
headline: params.headline,
|
||||
description: params.description,
|
||||
link: params.link,
|
||||
whatsapp_link: params.whatsapp_link,
|
||||
whatsapp_phone_number: params.whatsapp_phone_number,
|
||||
ad_account_id: params.ad_account_id,
|
||||
});
|
||||
} else {
|
||||
creative = await createAdCreative(client, {
|
||||
name: creativeName,
|
||||
page_id: params.page_id,
|
||||
instagram_actor_id: params.instagram_actor_id,
|
||||
instagram_actor_id: instagramActorId,
|
||||
image_hash: primaryImageHash,
|
||||
link: params.link,
|
||||
message: params.primary_text,
|
||||
|
|
@ -636,6 +640,23 @@ export async function addAdToAdSet(client: Client, params: AddAdToAdSetParams) {
|
|||
call_to_action_type: params.cta,
|
||||
ad_account_id: params.ad_account_id,
|
||||
});
|
||||
};
|
||||
|
||||
// 1815199: "A conta de anúncios não tem acesso a esta conta do Instagram".
|
||||
const isInstagramPermissionError = (err: unknown) =>
|
||||
err instanceof Error && /1815199/.test(err.message);
|
||||
|
||||
let creative;
|
||||
let instagramDropped = false;
|
||||
try {
|
||||
creative = await buildCreative(params.instagram_actor_id);
|
||||
} catch (err) {
|
||||
if (params.instagram_actor_id && isInstagramPermissionError(err)) {
|
||||
creative = await buildCreative(undefined);
|
||||
instagramDropped = true;
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
const creativeId = (creative as any)?.id;
|
||||
|
|
@ -659,6 +680,7 @@ export async function addAdToAdSet(client: Client, params: AddAdToAdSetParams) {
|
|||
adset_id: params.adset_id,
|
||||
creative_id: creativeId,
|
||||
ad_id: adId,
|
||||
instagram_dropped: instagramDropped,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue