API reference
Errors
Every error is { "error": { "code", "message" } } with a matching HTTP status. Switch on code, never on the message. No error uses credits.
curl "https://api.publicadsapi.com/v1/google/ads?keywords=travel" \ -H "authorization: Bearer $PADS_API_KEY"
400 Bad Request
{
"error": {
"code": "INVALID_INPUT",
"message": "keywords is not a parameter of GET /v1/google/ads. It takes: advertiser_id, domain, country, format, surface, political, date_from, date_to, cursor, include.",
"field": "keywords"
},
"credits_used": 0,
"credits_remaining": null
}Codes
| code | HTTP | When | What to do |
|---|---|---|---|
| INVALID_INPUT | 400 | A parameter missing, malformed or not taken by that platform. | Fix the parameter field names. Don't retry as it is. |
| INVALID_URL | 400 | A library URL we can't read. | Check the library address. Don't retry as it is. |
| UNAUTHENTICATED | 401 | No Authorization: Bearer <key> header. | Send Authorization: Bearer <key>. |
| INVALID_KEY | 401 | A key that is not ours, or was revoked. | Use a current key from Keys. |
| QUOTA_EXCEEDED | 402 | No credits left this month for this call. | Upgrade at upgrade_url, add a card at add_card_url, or wait for the 1st. Agents: give your user claim_url. |
| PAYMENT_REQUIRED | 402 | A paid plan whose latest invoice is unpaid. | Pay the latest invoice at upgrade_url. |
| AD_NOT_FOUND | 404 | No ad with that id. | Check the id. The ad may have been taken down: don't retry. |
| ENDPOINT_NOT_FOUND | 404 | No endpoint at that path. | Check the path, e.g. /v1/meta/ads. |
| RATE_LIMITED | 429 | Over the key's requests a second. | Wait Retry-After seconds, then retry. |
| UPSTREAM_BLOCKED | 503 | The platform blocked every attempt, on several connections. | Wait Retry-After seconds (about a minute), then retry. |
| UPSTREAM_CHANGED | 502 | The platform's page changed and we couldn't read it. | Retry later. We're alerted and fix it; meanwhile other platforms work. |
| TIMEOUT | 504 | The platform didn't answer within 60 seconds. | Retry once; if it times out again, narrow the search. |
| BUSY | 503 | Every one of our browsers is busy. | Wait Retry-After seconds (a few), then retry. |
| INTERNAL | 500 | Our fault. | Retry once, then write to us with the X-Request-Id. |
Retrying
- Retry:
RATE_LIMITED,BUSYandUPSTREAM_BLOCKEDafter theRetry-Afterheader's seconds;TIMEOUT,UPSTREAM_CHANGEDandINTERNALonce, after a pause. Back off if they repeat. - Don't retry: every other 4xx. The same request gets the same answer.
- Nothing is charged for any error, a block or a timeout included, so a retry costs only the call that succeeds.
- Set a 60 second timeout on your client. A live call can take 30 seconds or more when a platform blocks and we retry on new IPs; we answer
504 TIMEOUTat 60.
Other fields
| Field | On | What it is |
|---|---|---|
| error.field | INVALID_INPUT | The parameter at fault, as you named it. |
| error.upgrade_url | QUOTA_EXCEEDED, PAYMENT_REQUIRED | Where a person changes plan or pays. |
| error.add_card_url | QUOTA_EXCEEDED on Free | Where to add a card and pay for each extra credit. |
| error.claim_url | QUOTA_EXCEEDED for an agent | The link an AI agent gives its user to claim the account. |
| credits_used, credits_remaining | Search and one ad | 0 used, and what is left this month. |
Request ids
Every response to /v1 carries an X-Request-Id header. Put it in a message to support and we can find the call.