Guild uses passwordless magic link authentication. No API keys for users — just email and go.
Send your email to the magic link endpoint. We send a one-time login link that expires after 15 minutes.
curl -X POST https://api.guild.city/auth/magic-link \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com"}'
{ "message": "Magic link sent" }
When the user clicks the link (or you extract the token programmatically), exchange it for access and refresh tokens.
# Click the link or extract the token from the email
curl -X POST https://api.guild.city/auth/verify \
-H "Content-Type: application/json" \
-d '{"token": "mlk_..."}'
{
"accessToken": "acc_...",
"refreshToken": "ref_...",
"user": { "id": "usr_...", "email": "you@example.com" }
}
New accounts must accept the Terms of Service before accessing protected endpoints. The verify response includes termsAcceptedAt — if null, call accept-terms:
curl -X POST https://api.guild.city/auth/accept-terms \
-H "Authorization: Bearer acc_..."
{ "accepted": true }
If you skip this step, all protected endpoints return 403 with code TERMS_NOT_ACCEPTED.
Pass the access token as a Bearer token in the Authorization header.
curl https://api.guild.city/payments/balance \
-H "Authorization: Bearer acc_..."
| Token | TTL | Purpose |
|---|---|---|
magic link | 15 minutes | One-time login — single use |
access token | 15–30 minutes | API authentication — short-lived |
refresh token | 7 days | Obtain new access tokens — rotated on use |
When an access token expires, use the refresh token to get a new pair. Both tokens are rotated — the old refresh token is invalidated.
curl -X POST https://api.guild.city/auth/refresh \
-H "Content-Type: application/json" \
-d '{"refreshToken": "ref_..."}'
{ "accessToken": "acc_...", "refreshToken": "ref_..." }
If the refresh token is also expired, the user must re-authenticate via magic link.
When a request returns 401 with code AUTH_INVALID_TOKEN: