Connect an App Store Connect, Play Console or Apple Ads account (credentials are verified, then stored encrypted).
Credentials per provider (all are verified with one cheap read before anything is stored; they are encrypted with AES-256-GCM and never returned):
asc:{ issuer_id, key_id, private_key, vendor_number? }from App Store Connect → Users and Access → Integrations → App Store Connect API (role App Manager; Sales too for downloads/proceeds sync withvendor_numberfrom Payments and Financial Reports).appsdefaults to every app the key can see.play_console:{ service_account, reports_bucket? }= the Google Cloud service account JSON key, invited in Play Console → Users and permissions with View app information, Reply to reviews and Edit store listing.apps(package names) is required.reports_bucket(pubsite_prod_…) enables install stats.apple_ads:{ client_id, team_id, key_id, private_key, ad_account_id? }from Apple Ads → Account Settings → API for an API user with the API Account Manager role (Apple Ads Platform API;ad_account_idis needed when the user can access several ad accounts, the error lists them). Each linked app uses one of the plan's connected apps (limits.connections; Free 1, read-only). The default mode isactions(read_onlyon Free).
Request
curl -X POST "https://api.appgoat.ai/v1/connections" \
-H "x-api-key: $APPGOAT_API_KEY" \
-H "content-type: application/json" \
-d '{"provider":"asc","label":"My ASC key","credentials":{"issuer_id":"57246542-96fe-1a63-e053-0824d011072a","key_id":"2X9R4HXF34","private_key":"-----BEGIN PRIVATE KEY-----\n…\n-----END PRIVATE KEY-----"},"apps":["1234567890"]}'const res = await fetch("https://api.appgoat.ai/v1/connections", {
method: 'POST',
headers: {
"x-api-key": process.env.APPGOAT_API_KEY,
"content-type": "application/json",
},
body: JSON.stringify({"provider":"asc","label":"My ASC key","credentials":{"issuer_id":"57246542-96fe-1a63-e053-0824d011072a","key_id":"2X9R4HXF34","private_key":"-----BEGIN PRIVATE KEY-----\n…\n-----END PRIVATE KEY-----"},"apps":["1234567890"]}),
});
const { data, meta } = await res.json();import os, requests
res = requests.post(
"https://api.appgoat.ai/v1/connections",
headers={"x-api-key": os.environ["APPGOAT_API_KEY"]},
json={"provider":"asc","label":"My ASC key","credentials":{"issuer_id":"57246542-96fe-1a63-e053-0824d011072a","key_id":"2X9R4HXF34","private_key":"-----BEGIN PRIVATE KEY-----\n…\n-----END PRIVATE KEY-----"},"apps":["1234567890"]}
)
body = res.json()Request body
JSON, required.
providerProviderasc = App Store Connect, play_console = Google Play Console, apple_ads = Apple Ads (Search Ads).
labelstringYour name for it (default: provider + key / account).
mode"actions" | "read_only"credentialsobjectSee the description for the fields per provider.
appsstring[]Apps to link: App Store ids / bundle ids (asc, apple_ads) or package names (play_console, required).
Response
201 with data: Connection. See the envelope for meta.
idstringproviderProviderasc = App Store Connect, play_console = Google Play Console, apple_ads = Apple Ads (Search Ads).
labelstringmode"actions" | "read_only"status"active" | "invalid" | "deleted"accountobjectNon-secret identifiers (issuer_id, key_id, client_email, ad_account_id, ad_account_name, currency, …).
appsLinkedApp[]last_verified_atstring | nulllast_errorstring | nulllast_synced_atstring | nullLast downloads / proceeds sync (ASC with vendor_number
created_atstringavailable_appsLinkedApp[]Only on verify.
Example
{
"data": {
"id": "con_x8Hq2mXc0aLpQwRtYb",
"provider": "asc",
"label": "string",
"mode": "actions",
"status": "active",
"account": {},
"apps": [
{
"store": "apple",
"app_id": "324684580",
"external_id": "string",
"title": "Spotify: Music and Podcasts",
"bundle_id": "string"
}
],
"last_verified_at": "2026-10-22T10:00:00Z",
"last_error": "string",
"last_synced_at": "2026-10-22T10:00:00Z",
"created_at": "2026-10-22T10:00:00Z",
"available_apps": [
{
"store": "apple",
"app_id": "324684580",
"external_id": "string",
"title": "Spotify: Music and Podcasts",
"bundle_id": "string"
}
]
},
"meta": {
"credits_used": 0,
"credits_remaining": 9981,
"request_id": "req_123"
}
}Status codes
201
Connected and verified.
A parameter is missing or invalid (
error.param names it).Missing or invalid API key.
insufficient_credits (the call costs more than you have left; nothing was done) or plan_limit (a feature of a higher plan).422
The provider rejected the credentials, or a field is missing;
hint says where to find / fix it.429
rate_limitedToo many requests per second for your plan.
502
App Store Connect / Google Play / Apple Ads answered with an error (message passed through).