Create an Ad Account with the Meta API: Fields and Limits
To create an ad account with the Meta API, send POST /{business-id}/adaccount as a business admin with name, currency, timezone_id, end_advertiser, media_agency, and partner. Add funding_id or the account can't deliver. Meta caps how many ad accounts a business portfolio can create, often one at first, then you grant people access with assigned_users. Adeli wraps this in one idempotent call per customer.
To create an ad account with the Meta API, send POST /{business-id}/adaccount to the Marketing API as an admin of a business portfolio. The request needs six fields: name, currency, timezone_id, end_advertiser, media_agency, and partner. Meta limits how many ad accounts each business portfolio can create, and once the account exists you give people access through its assigned_users edge.
This guide is for developers at platforms that run ads for their own customers: what each field means, the limits you'll hit, and why most platforms create one ad account per customer. It's part of our Meta Ads API series.
What do you need before you start?
- A Meta app with Marketing API access. The ad account calls below run on the Marketing API, so your app needs
ads_managementandbusiness_management, both with Advanced Access through App Review. Our Meta app review guide covers that process. - A business portfolio ID. Ad accounts created through the API live inside a business portfolio (formerly Business Manager). Meta has no API for personal ad accounts.
- A business admin's token. Meta's ad accounts guide says you must be an admin of the business, and that shared admin logins can't create ad accounts.
- A business in good standing. Incomplete ad accounts, unpublished Pages, or an account under review in the same portfolio block creation.
Step 1: Create the ad account
Send a POST to the business's adaccount edge with the six required fields. The edge name is singular: adaccount, not adaccounts. This is the shape from Meta's business adaccount reference:
curl -X POST "https://graph.facebook.com/v26.0/$BUSINESS_ID/adaccount" \
-F "name=Customer 4821 - Ads" \
-F "currency=USD" \
-F "timezone_id=$TIMEZONE_ID" \
-F "end_advertiser=$CUSTOMER_PAGE_ID" \
-F "media_agency=NONE" \
-F "partner=NONE" \
-F "access_token=$ACCESS_TOKEN"A successful call returns the new account's id (in act_<digits> form), account_id, and business_id, plus the end_advertiser_id, media_agency_id, and partner_id you set.
Step 2: Choose the required fields
Three of the six required fields are entity fields that say who the ads are for, who buys them, and who helps. Get them right the first time, because some can't be changed later.
| Field | What it takes | Notes |
|---|---|---|
name |
A string | Shown in Ads Manager. Put your customer's ID in it so support can find it. |
currency |
An ISO 4217 code, such as USD |
Can't be changed after creation. |
timezone_id |
A numeric ID from Meta's time zone list | Not an IANA name. Insights are reported in this time zone. Can't be changed after creation. |
end_advertiser |
A Page ID, Page alias, or app ID, or NONE / UNFOUND |
The business the ads promote. Once set to a real ID, it can't be changed. |
media_agency |
Same values as end_advertiser |
The agency buying the ads, which may be your own business. |
partner |
Same values as end_advertiser |
Any other advertising partner. |
funding_id (optional) |
A payment method ID | Without one, ads can be created but won't deliver. |
invoice (optional) |
Boolean | Attaches the account to the business's credit line, if it has one. |
po_number (optional) |
A string | Purchase order number for invoiced accounts. |
NONE versus UNFOUND: use NONE when there's no advertiser, agency, or partner, and UNFOUND when there is one but it has no Facebook Page or app to point at.
How many ad accounts can a business create?
Meta caps the number of ad accounts each business portfolio can create, and the cap starts low. Meta's ad accounts guide says API creation is limited to 5 ad accounts, with more created manually. In practice the cap is often lower for a new portfolio:
"We all start with an ad account creation limit of one. That can increase once we've made our first confirmed payment." Jon Loomer, Meta ads consultant, Facebook Ad Account Creation Limit (updated March 2025)
For a platform, that means a customer's brand-new business portfolio may only be able to hold one ad account until it has paid for some ads. Plan for these errors from the reference:
- 3979. The business has used its allowed number of ad accounts. Show the customer a message that names the limit; retrying won't help.
- 3980. An existing ad account in the portfolio is in bad standing or under review. Every account has to be in good standing first.
- 415. Two-factor authentication is required on the person's account.
- 3902. A temporary technical issue. Retry with backoff.
Step 3: Assign people to the ad account
Grant access with POST /act_{ad-account-id}/assigned_users, passing a business-scoped user ID and a list of tasks. Send the same call with new tasks to change someone's access, and DELETE on the same edge to remove them.
curl -X POST "https://graph.facebook.com/v26.0/act_$AD_ACCOUNT_ID/assigned_users" \
-F "user=$BUSINESS_SCOPED_USER_ID" \
-F 'tasks=["ADVERTISE","ANALYZE"]' \
-F "access_token=$ACCESS_TOKEN"Meta's tasks map to three roles:
| Tasks | Role | What the person can do |
|---|---|---|
["ANALYZE"] |
Reporting only | See ad performance |
["ADVERTISE","ANALYZE"] |
General user | Create and edit ads on the account's funding source, but not account settings |
["MANAGE","ADVERTISE","ANALYZE"] |
Admin | Manage campaigns, reporting, billing, and account permissions |
GET on the same edge lists who has access. If your platform acts through a system user, assign that system user here too, or it won't see the new account.
Why should a platform create one ad account per customer?
One ad account per customer keeps each customer's money, limits, and data separate. An ad account is the unit Meta bills, caps, and reports on, so sharing one across customers mixes all three.
- Billing. Each account has its own payment method, so every customer pays Meta directly for their own spend.
- Spend caps. An account spending limit is a hard stop for that account. Per customer, it becomes a safety rail you can set from your product.
- Reporting. Insights roll up per account in the account's own time zone and currency, with no filtering needed to split customers apart.
- Blast radius. If Meta disables one account, the others keep delivering.
- Offboarding. A customer who leaves takes their account and its history with them.
The cost is the creation limit above, which is why your onboarding should handle a customer who already has an ad account as well as one who needs a new one.
How do you know it worked?
Read the new account back and check its status before you build campaigns in it. GET /act_{ad-account-id}?fields=name,currency,timezone_name,account_status should return account_status: 1 (active). Two problems show up later rather than at creation:
- Nothing delivers. The account has no payment method. Ask the customer to add one in Meta, or pass
funding_idwhen you create the account. - Your token can't see the account. The person or system user you're calling as wasn't assigned. Run Step 3 for them.
Is there a faster way to do this?
Adeli creates a customer's Meta ad account in one call, inside the business portfolio the customer connected. Adeli holds the Meta app and the ads_management and business_management grants, so you skip App Review and token storage. List the customer's portfolios with list businesses, then create the account with create ad account:
curl -X POST "https://app.tryadeli.com/api/v1/ads/accounts?accountId=$ACCOUNT_ID" \
-H "Authorization: Bearer $ADELI_API_KEY" \
-H "Idempotency-Key: customer-4821-ad-account" \
-H "Content-Type: application/json" \
-d '{"businessId":"1122334455","name":"Customer 4821 - Ads","timezone":"America/New_York","currency":"USD"}'What the endpoint handles for you:
- An
Idempotency-Keyheader is required. A retried create would be a second ad account eating into the limit, so the same key replays the original result instead. - IANA time zones. You pass
America/New_York, and Adeli maps it to Meta's numeric time zone ID. - A clear limit error. A portfolio at its cap returns
422 provider_rejected, so you can tell the customer why.
After that, update ad account renames an account or sets its spending limit, and list ad accounts returns every account the connection can reach. Payment methods and closing an account have no API, so customers do those in Meta. The same API key publishes posts and reads analytics, and pricing is per customer profile, so it follows how you bill.