The pain of integration with the Reddit API

nickdefo1 pts0 comments

Why the Reddit Ads API was harder than it looks

Why the Reddit Ads API was harder than it looks<br>We budgeted a day to integrate Reddit Ads and it took two weeks. Here are the refusals we hit, why our tests never caught them, and how it ends.<br>GT<br>Growomat Dev Team<br>Published August 10, 2026·Updated August 11, 2026·9 min read

Share

On this page

On this page

Share

We assumed integrating Reddit ads would be a walk in the park. Boy, were we wrong.

After successfully setting up Google Ads and Microsoft Advertising with their stable interfaces, Reddit was the obvious next step for Growomat - especially since both our dev team and our users love the platform.

Things looked promising at first. We spent a week building the platform adapter and mock services, estimating that hooking up the live APIs would only take about a day.

Two weeks later, and a lot more hair and sleep loss, we realised it was more<br>complicated than it looked.

If your team is integrating with the Reddit API, here are some lessons you can<br>learn from.

The Reddit API is a new interface

Claude and Codex know well-established APIs like Google Ads inside out. Reddit's<br>they don't - there simply isn't much Reddit API material in their training<br>data.

No problem - they should just pull the latest API documentation from the Reddit<br>developer portal so they know what to build?

Oops - next problem, the Reddit developer portal blocked our automated tooling<br>from retrieving the documentation.

We resolved this by downloading the full Reddit OpenAPI spec file and using that<br>file locally for integration. This is a good learning to speed things up instead<br>of a ton of online calls.

Once we got these basic interface issues sorted, we got to the next set of<br>issues - weird error messages.

Weird error messages

Because we care about our users' ad budgets and controlling their spending, we<br>set budget optimization on (is_campaign_budget_optimization = true).

However, this gave an error when creating the campaign:

Cap is required for Cost Cap campaigns

Campaigns with budget optimization turned on have to send bid_strategy and<br>bid_type. Ours sent neither, because the user hadn't configured any bidding at<br>all. What came back wasn't "bid_strategy is required".

So we thought - let's just set the automatic bidding strategy,<br>MAXIMIZE_VOLUME. However, it isn't; it is the Cost Cap product, and it wants<br>a cap. The automatic one is BIDLESS, which is what Reddit uses in every<br>template in its own campaign setup guide.

The OpenAPI description, meanwhile, says the cap is "Optional when bid_strategy<br>is MAXIMIZE_VOLUME", contradicting both the guide and the live API. Believing it<br>cost us a lot of debugging.

So when a platform complains about a field you never set, go looking for a<br>default you never chose. And when the reference disagrees with the vendor's own<br>worked examples, back the examples; they usually describe the system that's<br>actually running.

Absent, null and "inherit" are three different things

Campaign accepted. We moved down a level, and Reddit refused the ad group:

missing required attributes: bid_strategy, bid_type

Under budget optimization the money lives on the campaign, so why does the ad<br>group need bidding fields at all?

Because bid_strategy and bid_value have to go up as explicit nulls, and that<br>null is doing real work. It's how an ad group says "inherit from the campaign".<br>Leaving the keys out isn't the same as sending them empty. Our compact()<br>helper strips nulls, so we had to attach these fields after it ran.

Then the same distinction bit us from the other direction:

Ad group field optimization_goal must match the campaign value.

We were computing that field in two places under two different rules, so a<br>clicks campaign went up with no goal at all while its ad group confidently<br>asserted one.

The fix wasn't a better default. It was to send nothing at all in the normal<br>case. Campaigns already on Reddit were created before we sent that field and<br>hold whatever Reddit derived for them, so anything we invent might disagree.<br>Sending nothing can't disagree with anything, and the ad group inherits.

Lesson: find out whether your API distinguishes "key absent" from "key present,<br>value null". Your JSON serializer already has an opinion, and you probably<br>haven't read it.

One payload for create and update

We compiled a single payload and used it for both verbs. Two bugs came out of<br>that, and both stayed invisible until something got pushed a second time.

The first: our update carried create-only fields. Reddit accepts objective and<br>is_campaign_budget_optimization when you create a campaign, and rejects the<br>entire PATCH if either one comes back. Every update of a linked campaign 400'd.

The second is nastier. Our model has no start date, so start_time was<br>synthesized as "now" during translation, which is correct exactly once. Every<br>later PATCH synthesized a fresher "now" and marched the campaign's start past ad<br>groups created minutes or days...

reddit campaign from group bid_strategy field

Related Articles