Ads API v3 is generally available
Ads API v3 is ready for production. If you use v2, migrate to v3 by March 31, 2027.
A practical comparison of the Nextdoor Ads API v2 and v3 contracts.
Nextdoor Ads API v3 keeps the same core objects: advertisers, campaigns, ad groups, ads, creatives, media, audiences, and reports. It standardizes routes, methods, pagination, and request schemas:
- URLs identify the advertiser and resource.
- HTTP methods describe the operation.
- Lists use the same cursor pattern.
- Request bodies use typed, resource-specific schemas.
If you already use v2, the biggest change is not the data model. It is how you build each request.
This changelog covers the supported Nextdoor Ads API v3 developer contract. Use the published API reference for the complete list of available resources and fields.
In this doc
The Nextdoor v3 contract, at a glance
| Area | v2 | v3 | What changes for you |
|---|---|---|---|
| Base path | /v2/api/... | /api/v3/... | Update the path, then convert the route, not just the prefix. |
| Route style | Entity/action routes such as /campaign/create | Advertiser-scoped resources such as /advertisers/{advertiserId}/campaigns | Put scope and object identity in the URL. |
| HTTP methods | POST is used for many mutations | GET reads, POST creates, PUT updates, DELETE archives | Replace action-style POST calls with standard methods. |
| Advertiser scope | Often in the JSON body as advertiser_id | In the URL as {advertiserId} | Remove the duplicate advertiser ID from mutation bodies. |
| Object IDs | Often id in the body or an action URL | Typed path parameters such as {campaignId} | Move the object ID into the item URL. |
| List pagination | Legacy, endpoint-specific inputs | Cursor pagination with pageSize, cursor, and pageInfo | Follow pageInfo.endCursor until it is absent. |
| Query parameters | Legacy naming and placement | camelCase: pageSize, includeArchived, startTime, endTime | Update query builders and serializers. |
| JSON bodies | Mixed legacy contract | snake_case fields such as campaign_id and user_status | Keep body serialization separate from query serialization. |
| Status | Separate action-style POST routes | PUT .../{id}/status | Send user_status to the resource’s status route. |
| Archive | Legacy status/action behavior | DELETE .../{id} | Treat archive as a resource operation. |
| Contract source | Legacy schemas and endpoint behavior | Published schemas, route docs, and generated OpenAPI | The published contract and API behavior stay aligned. |
Resource map
The paths below include the runtime v3 prefix. Braced values are path parameters.
| Resource | Public v3 surface | Notes |
|---|---|---|
| Advertiser | GET /api/v3/advertisers/{advertiserId}; GET /api/v3/advertisers/{advertiserId}/stats; POST /api/v3/advertisers | Create uses the collection route; the new advertiser ID is not sent in the body. |
| Campaign | List, get, stats, create, update, status, archive | Collection: /api/v3/advertisers/{advertiserId}/campaigns; item: /campaigns/{campaignId}. |
| Ad group | List, get, stats, create, update, status, archive | Collection: /api/v3/advertisers/{advertiserId}/adgroups; item: /adgroups/{adgroupId}. Lists can filter by campaignId. |
| Ad | List, get, stats, create, update, status, archive | Collection: /api/v3/advertisers/{advertiserId}/ads; item: /ads/{adId}. Lists can filter by parentId. |
| Creative | List, get, stats, create, update, archive | Collection: /api/v3/advertisers/{advertiserId}/creatives; item: /creatives/{creativeId}. Creative formats follow the documented v3 creative types. |
| Media asset | List, get, upload, archive | Collection: /api/v3/advertisers/{advertiserId}/media; item: /media/{mediaId}. The examples here cover the public image flow. |
| Audience | Advertiser-scoped audience operations exposed by the documented schema | Use the documented audience fields and operations. |
| Targeting | Public geographic lookup resources | These routes return reference data; they do not mutate campaigns. |
| Reporting | Advertiser-scoped reports and report schedules | One-off reports, schedules, and generated reports are modeled as resources. |
Resource changes
Advertisers and scoped collections
V2 exposes many lists through entity/action routes. V3 nests collections under the advertiser:
TEXT
/api/v3/advertisers/{advertiserId}/campaigns
/api/v3/advertisers/{advertiserId}/adgroups
/api/v3/advertisers/{advertiserId}/ads
/api/v3/advertisers/{advertiserId}/creatives
That makes ownership part of the request instead of something the client has to infer from a body field or endpoint name.
Campaigns
| Operation | v2 | v3 |
|---|---|---|
| Get one | GET /v2/api/campaign/get/{id} | GET /api/v3/advertisers/{advertiserId}/campaigns/{campaignId} |
| Stats | GET /v2/api/campaign/get/{id}/stats | GET /api/v3/advertisers/{advertiserId}/campaigns/{campaignId}/stats?startTime=YYYY-MM-DD&endTime=YYYY-MM-DD |
| Create | POST /v2/api/campaign/create | POST /api/v3/advertisers/{advertiserId}/campaigns |
| Update | POST /v2/api/campaign/update | PUT /api/v3/advertisers/{advertiserId}/campaigns/{campaignId} |
| Status | POST /v2/api/campaign/status/update | PUT /api/v3/advertisers/{advertiserId}/campaigns/{campaignId}/status |
| Archive | Legacy action/status behavior | DELETE /api/v3/advertisers/{advertiserId}/campaigns/{campaignId} |
In v3, the create body carries campaign fields such as name, objective, and optional sub_objective. advertiser_id moves into the URL. Updates use a partial body; the public implementation currently exposes campaign name updates.
Ad groups
V3 turns the ad group into a first-class advertiser-scoped resource:
- GET /api/v3/advertisers/{advertiserId}/adgroups
- GET /api/v3/advertisers/{advertiserId}/adgroups/{adgroupId}
- GET /api/v3/advertisers/{advertiserId}/adgroups/{adgroupId}/stats
- POST /api/v3/advertisers/{advertiserId}/adgroups
- PUT /api/v3/advertisers/{advertiserId}/adgroups/{adgroupId}
- PUT /api/v3/advertisers/{advertiserId}/adgroups/{adgroupId}/status
- DELETE /api/v3/advertisers/{advertiserId}/adgroups/{adgroupId}
The create body keeps the parent relationship explicit with campaign_id. It also carries the ad group’s name, placements, bid, budget, schedule, frequency caps, targeting, and supported status fields. Updates are partial; send the fields you want to change instead of rebuilding the entire object.
Ads
| Operation | v2 | v3 |
|---|---|---|
| List | GET /v2/api/ad/list | GET /api/v3/advertisers/{advertiserId}/ads |
| Get one | GET /v2/api/ad/get/{id} | GET /api/v3/advertisers/{advertiserId}/ads/{adId} |
| Stats | GET /v2/api/ad/get/{id}/stats | GET /api/v3/advertisers/{advertiserId}/ads/{adId}/stats?startTime=YYYY-MM-DD&endTime=YYYY-MM-DD |
| Create | POST /v2/api/ad/create | POST /api/v3/advertisers/{advertiserId}/ads |
| Update | POST /v2/api/ad/update | PUT /api/v3/advertisers/{advertiserId}/ads/{adId} |
| Status | POST /v2/api/ad/status/update | PUT /api/v3/advertisers/{advertiserId}/ads/{adId}/status |
| Archive | Legacy action/status behavior | DELETE /api/v3/advertisers/{advertiserId}/ads/{adId} |
The v3 create body contains adgroup_id, creative_id, and name. The ad ID belongs in the URL for reads, updates, status changes, and archive operations.
Creatives
V2 accepts a broad legacy input shape. V3 uses typed creative bodies, so the API can validate fields for the selected creative type instead of accepting one catch-all payload.
The public image workflow is:
- Upload or identify the required image assets.
- Create the creative at /api/v3/advertisers/{advertiserId}/creatives.
- Pass asset IDs such as logo_image_id and canvas_image_id in the type-specific body.
- Update with PUT .../creatives/{creativeId} using the matching update body.
- Archive with DELETE .../creatives/{creativeId}.
Media assets
V3 separates asset lifecycle from creative lifecycle:
- GET /api/v3/advertisers/{advertiserId}/media
- GET /api/v3/advertisers/{advertiserId}/media/{mediaId}
- POST /api/v3/advertisers/{advertiserId}/media
- DELETE /api/v3/advertisers/{advertiserId}/media/{mediaId}
For images, upload first, save the returned media ID, and reference it from the creative request. Archiving a media asset does not archive a creative that already references it.
Audiences and targeting
V3 makes audience reads advertiser-scoped and applies the same cursor conventions used by other collections.
Targeting lookups also move to v3 resources. Store the returned IDs and names, then pass only the targeting fields supported by the public ad group schema.
Reporting
V2 uses reporting list and scheduled-report actions. V3 models reports and schedules as advertiser-scoped resources:
- GET /api/v3/advertisers/{advertiserId}/reports
- GET /api/v3/advertisers/{advertiserId}/reports/schedules
- GET /api/v3/advertisers/{advertiserId}/reports/schedules/{scheduleId}
- GET /api/v3/advertisers/{advertiserId}/reports/schedules/{scheduleId}/generated_reports
- POST /api/v3/advertisers/{advertiserId}/reports/schedules
- DELETE /api/v3/advertisers/{advertiserId}/reports/schedules/{scheduleId}
Use the documented reporting schema for report types, dimensions, metrics, filters, and output formats.
Behavior that changes everywhere
Pagination
V3 lists use cursor pagination:
TEXT
?pageSize=100&cursor=<opaque-cursor>
pageSize is required and must be between 1 and 500. The response includes pageInfo.endCursor. Treat that cursor as opaque: URL-encode it, send it back unchanged, and stop when it is absent.
Archived objects
Archived objects are excluded from default lists where the resource supports archive filtering. Add includeArchived=true when you need them. An archived object is not the same as a missing object; it remains an identifiable resource.
Stats date ranges
Stats routes use startTime and endTime query parameters in YYYY-MM-DD format. The end date is inclusive. Validate returned timestamps against the advertiser timezone rather than assuming raw UTC boundaries.
Errors
V3 failures return an api_error_code and a human-readable message. Branch on the code. Use the message for diagnostics, not as a stable identifier.
Benefits of v3
- Less guesswork: the URL tells you which advertiser and resource you are addressing.
- More reusable clients: list, update, status, archive, and stats patterns repeat across resources.
- Safer payloads: typed bodies catch invalid field combinations earlier.
- Predictable large-scale reads: cursor pagination avoids offset drift.
- Aligned contract: the published documentation, validation, and generated OpenAPI definition come from the same API contract.
Resources: Upgrade Guide · API reference · Questions? Email [email protected].