Skip to main content

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.

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-time keySecret)
  • 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 with plk_)
  • keySecret (starts with pls_, 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"
curl -X POST https://api.paylinks.ro/api/v1/auth/request \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]"}'
{"ok": true}

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

  1. Redirect the user to: GET /auth/google/start?redirectTo=https://yourapp.com/callback
  2. User completes Google consent
  3. Google redirects to /auth/google/callback with code and state
  4. 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

PropertyValue
TypeJWT (JSON Web Token)
Expiry (magic link / Google)7 days
Expiry (API key exchange)1 hour
AlgorithmHS256
RevocationBump 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.