Orbit now audits Braze translations and catalog references, and can replace an image or duplicate a campaign
Four new Braze tools cover the checks that usually happen by eye: translation coverage, catalog references in Liquid, swapping an image without breaking its URL, and copying a campaign without a timeout leaving a second copy. Four existing tools read more of your workspace, and if your key lacks a permission one of the new checks needs, that check is skipped and the rest of the call still runs. 88 skills and 140 tools now.
What shipped
•New: orbit_audit_braze_translations checks translation coverage across campaigns, Canvases, email templates and Content Blocks. It reports missing locales, empty entries, and translations whose Liquid no longer matches the source, such as a changed condition or a moved output. A large audit returns a partial result that names exactly what it did not read, rather than dropping it quietly.
•New: orbit_validate_braze_catalog_refs checks catalog_items, catalog_selection_items and items field reads against the catalogs that actually exist in your workspace, following them through if/else branches and loops, with line numbers. Selections are checked only when Braze returns them, because Braze's API has no endpoint that lists selections.
•New: orbit_replace_braze_image replaces the file behind a Media Library image while keeping its asset id and URL. It is a dry run by default and replaces only with confirm set to true. Know what that means before you confirm: emails already delivered show the new image when next opened, and Braze keeps no copy of the old file. Orbit never retries the write, and if the result is uncertain it tells you to check the Media Library before trying again.
•New: orbit_duplicate_braze_campaign reads the source, states what would be copied, and is a dry run by default. If the request cannot finish inside its time budget, Orbit does not send it, so a timeout cannot leave you with a second copy. An interrupted request tells you to check the dashboard before retrying. Braze does not document what state the copy starts in, and the tool says so instead of guessing.
•Improved: orbit_validate_test_users reports each seed's subscription group states and flags seeds that are unsubscribed. orbit_audit_preference_centre lists the subscription groups each centre references, with a caveat: Braze's group state does not reflect a global email unsubscribe. orbit_audit_braze_instance adds failed or stale Cloud Data Ingestion syncs and a count of SMS invalid numbers. orbit_braze_performance adds uninstalls, purchase volume and the product list, plus send-level stats for API campaign sends through a new optional sends input.
•Behaviour change: orbit_braze_performance's days input now accepts 1 to 100. That is Braze's own limit, and anything above 100 was already failing at Braze.
•Bug fix: Braze error messages that arrived as objects showed as "[object Object]". They now show Braze's actual message.
•Setup note: some of this needs new API key permissions: campaigns.translations.get, canvas.translations.get, templates.translations.get, content_blocks.translations.get, catalogs.get, media_library.replace, campaigns.duplicate, subscription.groups.get, subscription.status.get, cdi.integration_list, cdi.integration_job_status, sms.invalid_phone_numbers, kpi.uninstalls.data_series, purchases.product_list, purchases.quantity_series and sends.data_series. Without one, that part of the result reports "skipped" and names the permission, and the rest of the call still runs.