401 or 403 — see Errors.
- The partner key/secret is a long-lived credential issued to your app. Treat the secret like a password: it is shown once at provisioning time and stored only as a bcrypt hash, so it cannot be recovered — only rotated.
- The user token is a short-lived (≈1 hour) OAuth access token that represents the Daysync user who authorized your app. All data access is scoped to what that user can see and do in Daysync.
The partner credential carries your granted scopes, which gate endpoint access. See Scopes & Permissions.
Partner credentials
Partner credentials are issued through the Daysync Integrations Portal. A credential has:- an API key (
dk_live_…) sent inx-api-key, - an API secret (
ds_…) sent inx-api-secret, - a set of scopes,
- an optional expiry.
403 Forbidden (a bare { "message": "Forbidden" } body) — only a missing API key returns 401. See Errors.
Obtaining credentials
Apply for partner credentials in the Integrations Portal. Once your application is approved you receive:User token — OAuth 2.0 Authorization Code flow (with PKCE)
Daysync users authorize your app through the Daysync Integrations Portal: a branded Daysync sign-in followed by a consent screen listing the permissions you request. Your backend then exchanges the returned authorization code for tokens. Your existing partner credential doubles as your OAuth client — there is no separate OAuth registration:PKCE is mandatory. Every authorize request must carry
code_challenge (S256) and every token exchange the matching code_verifier. Requests without S256 PKCE are rejected with invalid_request.Redirect (callback) URI
The OAuth flow requires a redirect URI — it’s where Daysync sends the user after they approve access, appending the authorization?code=… that your backend exchanges for tokens.
Register it yourself, instantly. Open your app in the Integrations Portal, add your callback under Redirect URIs, and save — the allowlist takes effect immediately, no Daysync review needed. HTTPS is required (http://localhost is permitted for development). An authorize request whose redirect_uri is not on your app’s list is rejected before any redirect happens (“This application’s redirect URL is not registered”).
Requestable scopes
Request scopes space-separated in thescope parameter — ask only for what you need. The two OpenID scopes plus the 14 Daysync API scopes are available:
The consented scope is clamped to what your partner credential is granted: scopes you request beyond your credential’s grant are silently dropped from the consent screen and the issued token. Endpoint access is ultimately gated by your partner scopes (see Scopes & Permissions).
Step 1 — Redirect the user to the portal
Generate a PKCE pair (code_verifier = random 43–128 chars; code_challenge = base64url(SHA-256(verifier))), then send the user to:
Step 2 — Receive the authorization code
After the user approves, the browser is redirected to yourredirect_uri with ?code=AUTH_CODE&state=… appended. If they decline, you receive ?error=access_denied instead. Codes are short-lived (5 minutes) — exchange promptly.
Step 3 — Exchange the code for tokens
Authenticate the client with HTTP Basic auth (-u) using your API key and secret, and include the PKCE code_verifier:
access_token as your Authorization: Bearer token, and treat scope as the authoritative record of what the user consented to.
expires_in reflects the actual remaining life of the issued token and can be shorter than the nominal hour. Track it and refresh when it approaches zero rather than assuming 3600.Step 4 — Refresh the token
Access tokens expire after ≈1 hour; the refresh token is valid for 30 days. Exchange a valid refresh token for a new access token (no user interaction needed):scope field). If the refresh token itself has expired, you receive 400 invalid_grant — restart the flow from Step 1.
Calling the API
Once you have an access token, every API call needs the bearer token and your partner key/secret:Postman setup
Remember to add your Postman callback URL (
https://oauth.pstmn.io/v1/callback) to your app’s Redirect URIs in the portal first. After Postman completes the OAuth exchange, set the obtained access_token as a Bearer token and add your x-api-key / x-api-secret headers, then call the API.
How the token is validated
The API verifies the bearer token on every call:- signature against the published JWKS,
- issuer matches the Daysync user pool,
token_useisaccess,- token has not expired.
401.
CORS
The API answersOPTIONS preflight requests with 204 before any authentication, and successful API responses include Access-Control-Allow-Origin: *.

