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:
Marcio Bevervanso 2026-06-08 14:21:18 -03:00
parent dcaf7959ac
commit a88e96adf5
2 changed files with 49 additions and 18 deletions

View file

@ -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> 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>
) : (

View file

@ -608,12 +608,16 @@ export async function addAdToAdSet(client: Client, params: AddAdToAdSetParams) {
// the most broadly compatible across placements.
const primaryImageHash = imageHashes[0];
let creative;
// 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) {
creative = await createWhatsappAdCreative(client, {
return createWhatsappAdCreative(client, {
name: creativeName,
page_id: params.page_id,
instagram_actor_id: params.instagram_actor_id,
instagram_actor_id: instagramActorId,
image_hash: primaryImageHash,
message: params.primary_text,
headline: params.headline,
@ -623,11 +627,11 @@ export async function addAdToAdSet(client: Client, params: AddAdToAdSetParams) {
whatsapp_phone_number: params.whatsapp_phone_number,
ad_account_id: params.ad_account_id,
});
} else {
creative = await createAdCreative(client, {
}
return 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,
};
}