GET /v1/social/oauth-status/:state
Poll the state of a pending OAuth handshake by state token.
GET
/v1/social/oauth-status/:statePhase 1stable
- Auth
- Bearer
- Scope
- social:read
Poll this endpoint with the state you got back from POST /v1/projects/:id/social/oauth-url to learn whether the end-customer completed consent and, if so, which socialAccountId was created.
The endpoint is not project-scoped — the state token uniquely identifies the attempt, and Layers scopes results by the API key that created it (a state created under key A is invisible to key B).
Poll at 2-second intervals with jitter for up to 10 minutes. After that, the state expires and you create a new URL. Don't poll faster than once per second per state.
Path
statestringrequiredOpaque state token from oauth-url. Case-sensitive.
Example request
curl "https://api.layers.com/v1/social/oauth-status/st_01HXZ8K2M4P5QRS6TUV7WXYZ9A" \
-H "Authorization: Bearer lp_live_01HX9Y6K7EJ4T2_4QZpN..."async function waitForOAuth(state: string) {
const deadline = Date.now() + 10 * 60 * 1000;
while (Date.now() < deadline) {
const status = await layers.social.getOAuthStatus({ state });
if (status.status === "completed") return status.socialAccountId;
if (status.status === "failed") throw new Error(status.error?.message ?? "OAuth failed");
await new Promise((r) => setTimeout(r, 2000 + Math.random() * 500));
}
throw new Error("OAuth timed out");
}import time, random
def wait_for_oauth(state: str) -> str:
deadline = time.time() + 600
while time.time() < deadline:
status = layers.social.get_oauth_status(state=state)
if status["status"] == "completed":
return status["socialAccountId"]
if status["status"] == "failed":
raise RuntimeError(status.get("error", {}).get("message", "OAuth failed"))
time.sleep(2 + random.random() * 0.5)
raise TimeoutError("OAuth timed out")Response
200Pending — keep polling
{
"state": "st_01HXZ8K2M4P5QRS6TUV7WXYZ9A",
"status": "pending",
"expiresAt": "2026-04-18T19:12:11Z"
}200Completed — account connected
{
"state": "st_01HXZ8K2M4P5QRS6TUV7WXYZ9A",
"status": "completed",
"socialAccountId": "sa_01HXZ9P2M4N5KLM6TUV7WXYZ9A",
"platform": "tiktok",
"handle": "acmecoffee",
"connectedAt": "2026-04-18T19:06:42Z"
}200Failed — user denied or platform rejected
{
"state": "st_01HXZ8K2M4P5QRS6TUV7WXYZ9A",
"status": "failed",
"error": {
"code": "USER_DENIED",
"message": "The user did not grant consent on the platform."
}
}Errors
| Status | Code | When |
|---|---|---|
| 401 | UNAUTHENTICATED | Missing or invalid key. |
| 403 | FORBIDDEN_SCOPE | Key lacks social:read. |
| 404 | NOT_FOUND | state unknown, expired, or created under a different project. |
| 429 | RATE_LIMITED | Polling budget exhausted — back off with the Retry-After header. |
See also
POST /v1/projects/:id/social/oauth-url— create the URLGET /v1/projects/:id/social-accounts— enumerate connected accounts