Authentication
PayLinks uses JWT bearer tokens for API authentication.
- For web users: magic link or Google OAuth.
- For integrations/agents: create API keys in Dashboard Profile, then exchange key credentials for short-lived JWTs.
API Key Flow (Recommended for Integrations)
This flow is designed for server-to-server integrations and AI agents.
0. (Optional) Programmatic signup in one call
If the developer does not already have a PayLinks account, create account + first API key directly:
curl -X POST https://api.paylinks.ro/api/v1/auth/api/signup \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","name":"Dev","keyName":"Primary integration"}'
This returns:
- account info
- first API key (
keyId+ one-timekeySecret) - short-lived JWT for immediate use
1. Create an API key in Dashboard
Go to Dashboard -> Profile -> API Access and create a key.
You receive:
keyId(starts withplk_)keySecret(starts withpls_, shown only once)
2. Exchange API key for JWT
curl -X POST https://api.paylinks.ro/api/v1/auth/api/token \
-H "Content-Type: application/json" \
-d '{"keyId":"plk_xxx","keySecret":"pls_xxx"}'
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"tokenType": "Bearer",
"expiresInSeconds": 3600,
"user": {
"id": "user_123",
"email": "[email protected]",
"role": "USER"
}
}
3. Use JWT as Bearer token
curl https://api.paylinks.ro/api/v1/paylinks \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "X-Currency: RON"
Magic Link Flow
1. Request a Magic Link
curl -X POST https://api.paylinks.ro/api/v1/auth/request \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]"}'
{"ok": true}
2. User Clicks Email Link
The email contains a link pointing to the verify endpoint with the token query parameter.
3. Verify and Get JWT
curl "https://api.paylinks.ro/api/v1/auth/verify?token=MAGIC_TOKEN"
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"needsOnboarding": false
}
Google OAuth Flow
Standard OAuth
- Redirect the user to:
GET /auth/google/start?redirectTo=https://yourapp.com/callback - User completes Google consent
- Google redirects to
/auth/google/callbackwithcodeandstate - The API returns a JWT token
Google One Tap
curl -X POST https://api.paylinks.ro/api/v1/auth/google/onetap \
-H "Content-Type: application/json" \
-d '{"credential": "GOOGLE_ONE_TAP_JWT"}'
Using the Token
Include the JWT in the Authorization header for all protected endpoints:
curl https://api.paylinks.ro/api/v1/me \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
X-Currency Header
Set the currency context with the X-Currency header:
curl https://api.paylinks.ro/api/v1/paylinks \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Currency: EUR"
Supported values: RON (default), EUR, GBP.
This header affects which currency is used when creating payment links and how monetary values are returned.
Token Lifecycle
| Property | Value |
|---|---|
| Type | JWT (JSON Web Token) |
| Expiry (magic link / Google) | 7 days |
| Expiry (API key exchange) | 1 hour |
| Algorithm | HS256 |
| Revocation | Bump user's tokenVersion to invalidate all tokens |
Tokens are stateless. There is no refresh token flow — request a new magic link or re-authenticate via Google OAuth when the token expires.
Error Responses
Missing or invalid token:
{
"error": {
"message": "Unauthorized",
"code": "UNAUTHORIZED"
}
}
HTTP status: 401
Frequently Asked Questions
How long do JWT tokens last?
PayLinks JWT tokens from magic link / Google expire after 7 days. JWT tokens from API key exchange expire after 1 hour.
When your token expires:
- Web flow: request a new magic link or re-authenticate via Google OAuth.
- API flow: exchange your API key credentials again at
POST /auth/api/token.
How do I revoke a token?
To invalidate all tokens for a user, increment the user's tokenVersion field. This immediately revokes every previously issued JWT for that account, forcing re-authentication.
What happens when my token expires?
API requests with an expired token return a 401 Unauthorized response with the error code UNAUTHORIZED. Your application should catch this error and redirect the user to re-authenticate via magic link or Google OAuth.