v1.0 draftDownloads
Guide

Authentication

Registration, login, token refresh, logout, password reset, identifiers, and device registration.

YCMT-EU Developer Package — Authentication Guide

Version: v1.0 draft

API host: https://api.yes.cash

Audience: Partner technical teams building customer-facing integration apps.

---

1. Purpose

This guide explains how the partner customer app integrates with the YCMT-EU Authentication API.

Use this guide to implement:

  • customer registration;
  • customer login;
  • token refresh;
  • logout;
  • password reset;
  • customer identifier management;
  • device registration for transfer confirmation.

The Authentication API is exposed under:

https://api.yes.cash/v1/auth

---

2. Authentication model

The partner app presents the customer-facing UX and calls the YCMT-EU API.

YCMT-EU returns access and refresh tokens after successful registration or login. The partner app then uses the access token to call customer-authenticated API endpoints.

Basic model:

Customer enters credentials in partner app
  -> Partner app calls YCMT Auth API
  -> YCMT Auth API returns accessToken + refreshToken
  -> Partner app calls YCMT Core API with Authorization: Bearer <accessToken>

The partner app must treat tokens as bearer credentials.

Do:

  • store tokens securely;
  • refresh access tokens before or after expiry;
  • delete local tokens on logout;
  • pass the access token in the Authorization header.

Do not:

  • use token claims for authorization decisions;
  • expose tokens in logs;
  • send tokens to the partner backend unless explicitly required by the approved integration design;
  • store tokens in insecure browser storage.

---

3. Required headers

3.1 Public Auth calls

The following endpoints do not require a bearer token:

POST /v1/auth/start
POST /v1/auth/login
POST /v1/auth/register/start
POST /v1/auth/register/verify-otp
POST /v1/auth/register/set-password
POST /v1/auth/password/forgot
POST /v1/auth/password/reset

Use these headers:

Content-Type: application/json
Accept: application/json
Ocp-Apim-Subscription-Key: <partner-api-subscription-key>
X-Correlation-Id: <uuid-v4>

3.2 Customer-authenticated Auth calls

The following endpoints require a customer access token:

POST /v1/auth/refresh
POST /v1/auth/logout
GET  /v1/auth/identifiers
POST /v1/auth/identifiers/add/start
POST /v1/auth/identifiers/add/verify-otp
POST /v1/auth/identifiers/{identifierId}/remove/start
POST /v1/auth/identifiers/{identifierId}/remove/verify-otp
POST /v1/auth/device-registration/start
POST /v1/auth/device-registration/complete

Use these headers:

Content-Type: application/json
Accept: application/json
Authorization: Bearer <accessToken>
Ocp-Apim-Subscription-Key: <partner-api-subscription-key>
X-Correlation-Id: <uuid-v4>

---

4. Identifier format

The Auth API supports two customer identifier types:

TypeFormatExample
EMAILEmail addressalice@example.com
PHONEE.164 phone number+34612345678

Recommended partner-app behavior:

  • ask the customer whether they are using email or phone;
  • send identifierType explicitly;
  • normalise email to lowercase before sending;
  • send phone numbers in E.164 format.

Example:

{
  "identifier": "alice@example.com",
  "identifierType": "EMAIL"
}

---

5. Login flow

Login is a two-step flow.

POST /v1/auth/start
POST /v1/auth/login

5.1 Step 1 — Start login

Endpoint:

POST https://api.yes.cash/v1/auth/start

Request:

{
  "identifier": "alice@example.com",
  "identifierType": "EMAIL"
}

Successful response:

{
  "loginAttemptId": "LA-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "loginAttemptExpiresAt": "2026-05-11T14:10:12Z"
}

Partner-app behavior:

  • store loginAttemptId temporarily;
  • move the customer to the password screen;
  • do not show whether the identifier exists or not;
  • restart the login if loginAttemptExpiresAt passes.

5.2 Step 2 — Complete login

Endpoint:

POST https://api.yes.cash/v1/auth/login

Request:

{
  "loginAttemptId": "LA-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "password": "AliceStr0ngP@ssw0rd!"
}

Successful authenticated response:

{
  "authStatus": "AUTHENTICATED",
  "accessToken": "<accessToken>",
  "refreshToken": "<refreshToken>",
  "tokenType": "Bearer",
  "expiresIn": 3600,
  "accessTokenExpiresAt": "2026-05-11T15:00:00Z",
  "refreshTokenExpiresAt": "2026-06-10T14:00:00Z",
  "subscriptionId": "SUB-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "customerStatus": "PENDING"
}

Partner-app behavior:

  • store accessToken and refreshToken securely;
  • store subscriptionId as the partner-facing customer reference;
  • use customerStatus to decide the next UX step;
  • call Core API using Authorization: Bearer <accessToken>.

---

6. MFA outcomes during login

The /v1/auth/login response is polymorphic. The partner app must support all documented authStatus values.

authStatusMeaningPartner-app action
AUTHENTICATEDLogin succeededStore tokens and continue.
MFA_CHALLENGE_REQUIREDCustomer must enter MFA codeAsk for the MFA code and call /v1/auth/login again.
MFA_ENROLMENT_REQUIREDCustomer must enrol MFAShow supported methods, complete enrolment, then call /v1/auth/login again.

6.1 MFA challenge required

Example response:

{
  "authStatus": "MFA_CHALLENGE_REQUIRED",
  "mfaChallengeId": "MFC-01HX9J5Q1R7S9T1U3V5W7X9Y1Z",
  "mfaMethod": "TOTP",
  "mfaChallengeExpiresAt": "2026-05-11T14:05:00Z"
}

Follow-up request:

{
  "loginAttemptId": "LA-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "mfaChallengeId": "MFC-01HX9J5Q1R7S9T1U3V5W7X9Y1Z",
  "mfaMethod": "TOTP",
  "mfaCode": "847291"
}

6.2 MFA enrolment required

Example response:

{
  "authStatus": "MFA_ENROLMENT_REQUIRED",
  "mfaEnrolmentSessionId": "MFE-01HX9K7S2T9U1V3W5X7Y9Z1A3B",
  "supportedMethods": ["TOTP", "SMS_MFA"],
  "mfaEnrolmentSessionExpiresAt": "2026-05-11T14:05:00Z"
}

Follow-up request:

{
  "loginAttemptId": "LA-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "mfaEnrolmentSessionId": "MFE-01HX9K7S2T9U1V3W5X7Y9Z1A3B",
  "mfaEnrolmentMethod": "TOTP",
  "mfaEnrolmentCode": "319847"
}

---

7. New customer registration flow

Registration is a three-step flow.

POST /v1/auth/register/start
POST /v1/auth/register/verify-otp
POST /v1/auth/register/set-password

After registration succeeds, the partner app should prompt the customer to register their device.

7.1 Step 1 — Start registration

Endpoint:

POST https://api.yes.cash/v1/auth/register/start

Request:

{
  "identifier": "alice@example.com",
  "identifierType": "EMAIL",
  "partnerCustomerRef": "PARTNER-ALICE-001"
}

partnerCustomerRef is optional. Use it only as your own opaque reference for reconciliation or support.

Successful response:

{
  "registrationId": "RG-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "next": "OTP",
  "registrationIdExpiresAt": "2026-05-11T14:35:12Z"
}

Partner-app behavior:

  • ask the customer to enter the OTP sent through the selected channel;
  • keep registrationId temporarily;
  • restart registration if the session expires.

7.2 Step 2 — Verify registration OTP

Endpoint:

POST https://api.yes.cash/v1/auth/register/verify-otp

Request:

{
  "registrationId": "RG-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "otp": "123456"
}

Successful response:

{
  "registrationId": "RG-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "branch": "NEW_CUSTOMER",
  "next": "SET_PASSWORD"
}

Possible branch values:

branchMeaningPartner-app action
NEW_CUSTOMERIdentifier belongs to a new customer pathAsk the customer to set a password.
EXISTING_CUSTOMERIdentifier belongs to an existing customer pathAsk the customer to verify their password or follow the returned next step.

7.3 Step 3 — Set password

Endpoint:

POST https://api.yes.cash/v1/auth/register/set-password

Request:

{
  "registrationId": "RG-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "password": "AliceStr0ngP@ssw0rd!"
}

Successful response:

{
  "accessToken": "<accessToken>",
  "refreshToken": "<refreshToken>",
  "tokenType": "Bearer",
  "expiresIn": 3600,
  "accessTokenExpiresAt": "2026-05-11T15:00:00Z",
  "refreshTokenExpiresAt": "2026-06-10T14:00:00Z",
  "subscriptionId": "SUB-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "customerStatus": "PENDING"
}

Partner-app behavior:

  • store tokens securely;
  • store subscriptionId as the partner-facing customer reference;
  • continue to device registration;
  • then continue to profile and KYC.

---

8. Token refresh

Access tokens are short-lived. Use refresh when the access token is near expiry or after receiving auth.tokenExpired.

Endpoint:

POST https://api.yes.cash/v1/auth/refresh

Headers:

Authorization: Bearer <accessToken>
Ocp-Apim-Subscription-Key: <partner-api-subscription-key>
X-Correlation-Id: <uuid-v4>

Request:

{
  "refreshToken": "<refreshToken>"
}

Successful response:

{
  "accessToken": "<newAccessToken>",
  "refreshToken": "<newRefreshToken>",
  "tokenType": "Bearer",
  "expiresIn": 3600,
  "accessTokenExpiresAt": "2026-05-11T16:00:00Z"
}

Partner-app behavior:

  • replace the stored access token;
  • replace the stored refresh token if a new one is returned;
  • retry the original customer action after a successful refresh;
  • if refresh fails, clear local tokens and ask the customer to log in again.

---

9. Logout

Logout revokes the current refresh token and ends the local customer session.

Endpoint:

POST https://api.yes.cash/v1/auth/logout

Request:

{
  "refreshToken": "<refreshToken>"
}

Successful response:

204 No Content

Partner-app behavior:

  • call /v1/auth/logout where possible;
  • delete local access and refresh tokens;
  • clear sensitive customer session state;
  • redirect the customer to the logged-out screen.

If logout cannot be completed because the network is unavailable, the app must still delete local tokens.

---

10. Password reset

Password reset is a two-step flow.

POST /v1/auth/password/forgot
POST /v1/auth/password/reset

10.1 Step 1 — Start password reset

Endpoint:

POST https://api.yes.cash/v1/auth/password/forgot

Request:

{
  "identifier": "alice@example.com",
  "identifierType": "EMAIL"
}

Successful response:

{
  "passwordResetId": "PR-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "next": "OTP",
  "passwordResetIdExpiresAt": "2026-05-11T14:35:12Z"
}

Partner-app behavior:

  • ask the customer to enter OTP;
  • do not reveal whether the identifier exists;
  • continue to /password/reset.

10.2 Step 2 — Complete password reset

Endpoint:

POST https://api.yes.cash/v1/auth/password/reset

Request:

{
  "passwordResetId": "PR-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "otp": "123456",
  "newPassword": "NewStr0ngP@ssw0rd!"
}

Successful standalone response:

{
  "next": "LOGIN"
}

Partner-app behavior:

  • ask the customer to log in with the new password;
  • clear any existing local tokens for this customer.

---

11. Identifier management

Identifier management requires an authenticated customer session.

11.1 List identifiers

Endpoint:

GET https://api.yes.cash/v1/auth/identifiers

Successful response:

{
  "identifiers": [
    {
      "identifierId": "ID-01HX9F2J7K3M5N7P9Q1R3T5V7W",
      "identifierType": "EMAIL",
      "identifierMasked": "a***e@example.com",
      "verifiedAt": "2026-05-11T14:00:00Z",
      "canRemove": true
    }
  ]
}

Partner-app behavior:

  • display masked identifiers;
  • allow removal only when canRemove is true;
  • never display raw identifiers unless entered by the customer in the current screen.

11.2 Add identifier

Step 1:

POST https://api.yes.cash/v1/auth/identifiers/add/start

Request:

{
  "identifier": "+34612345678",
  "identifierType": "PHONE"
}

Successful response:

{
  "identifierAddId": "IAD-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "next": "OTP",
  "identifierAddIdExpiresAt": "2026-05-11T14:35:12Z"
}

Step 2:

POST https://api.yes.cash/v1/auth/identifiers/add/verify-otp

Request:

{
  "identifierAddId": "IAD-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "otp": "123456"
}

Partner-app behavior:

  • refresh the identifier list after success;
  • show only masked values in account settings.

11.3 Remove identifier

Step 1:

POST https://api.yes.cash/v1/auth/identifiers/{identifierId}/remove/start

Request:

{
  "otpDeliveryIdentifierId": "ID-01HX9F2J7K3M5N7P9Q1R3T5V7W"
}

Successful response:

{
  "identifierRemoveId": "IRD-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "next": "OTP",
  "otpDeliveryIdentifierMasked": "a***e@example.com",
  "identifierRemoveIdExpiresAt": "2026-05-11T14:35:12Z"
}

Step 2:

POST https://api.yes.cash/v1/auth/identifiers/{identifierId}/remove/verify-otp

Request:

{
  "identifierRemoveId": "IRD-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "otp": "123456"
}

Successful response:

{
  "identifierId": "ID-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "deactivatedAt": "2026-05-11T14:22:00Z"
}

Partner-app behavior:

  • do not allow the customer to remove the last usable identifier;
  • rely on the canRemove flag from the list endpoint;
  • refresh the list after successful removal.

---

12. Device registration

Device registration is required before the customer can complete device-bound transfer confirmation.

Device registration requires an authenticated customer session.

Flow:

POST /v1/auth/device-registration/start
POST /v1/auth/device-registration/complete

The detailed JWS construction is covered in 08_Device_Bound_Authentication.md. This section explains the Auth API flow only.

12.1 Start device registration

Endpoint:

POST https://api.yes.cash/v1/auth/device-registration/start

Request:

{
  "deviceMetadata": {
    "deviceModel": "iPhone 15",
    "osVersion": "iOS 18.4",
    "appVersion": "1.0.0",
    "platform": "iOS"
  }
}

Successful first-device response:

{
  "deviceRegistrationId": "DRG-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "registrationChallenge": "Y2hhbGxlbmdlLWJhc2U2NHVybC1lbmNvZGVkLTMyLWJ5dGVz",
  "expiresAt": "2026-05-11T15:13:22Z",
  "publicKeyRequirements": {
    "algorithm": "RS256",
    "minimumModulusBits": 2048,
    "recommendedModulusBits": 3072
  },
  "stepUpApplied": false
}

Partner-app behavior:

  • generate an RSA key pair on the customer device;
  • keep the private key on the device;
  • build a public JWK from the public key;
  • sign the registration challenge to produce registrationProof;
  • call /device-registration/complete before expiresAt.

12.2 Step-up required response

If an active device already exists, the API may require a liveness step-up before replacing it.

Response:

{
  "stepUpRequired": "LIVENESS_CHECK",
  "kycSessionId": "KYC-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "livenessWebviewUrl": "https://api.yes.cash/webviews/kyc/KYC-01HX...",
  "expiresAt": "2026-05-11T15:13:22Z",
  "nextStep": "OPEN_LIVENESS_WEBVIEW"
}

Partner-app behavior:

  • open the returned liveness webview;
  • collect the returned stepUpToken after successful webview completion;
  • call /device-registration/start again with stepUpToken.

Retry request:

{
  "stepUpToken": "<stepUpToken>",
  "deviceMetadata": {
    "deviceModel": "iPhone 15",
    "osVersion": "iOS 18.4",
    "appVersion": "1.0.0",
    "platform": "iOS"
  }
}

12.3 Complete device registration

Endpoint:

POST https://api.yes.cash/v1/auth/device-registration/complete

Request:

{
  "deviceRegistrationId": "DRG-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "publicKey": {
    "kty": "RSA",
    "n": "<base64url modulus>",
    "e": "AQAB",
    "kid": "device-key-2026-05-11",
    "alg": "RS256",
    "use": "sig"
  },
  "registrationProof": "<compact-jws>"
}

Successful response:

{
  "deviceId": "DEV-01HX9F2J7K3M5N7P9Q1R3T5V7W",
  "registeredAt": "2026-05-11T15:10:00Z",
  "publicKeyThumbprint": "8mAhQjJyZmJVZkRDeXBKVnpQUFhMQ3JJVnFKUzRSdTk",
  "stepUpApplied": false,
  "priorDeviceIdDeactivated": null
}

Partner-app behavior:

  • store deviceId locally;
  • keep the private key in secure device storage;
  • use the private key later to sign transfer confirmation assertions;
  • never export or transmit the private key.

---

13. Token and session storage guidance

13.1 Mobile apps

Recommended storage:

ItemRecommended storage
Access tokenSecure storage / keychain-backed storage
Refresh tokenSecure storage / keychain-backed storage
Device private keyOS keychain / secure enclave / Android Keystore where available
subscriptionIdApp secure profile/session storage
deviceIdApp secure profile/session storage

13.2 Web apps

Recommended behavior:

  • prefer secure, httpOnly, same-site cookies where the integration design supports it;
  • avoid localStorage for long-lived tokens;
  • clear tokens on logout;
  • avoid including tokens in URLs;
  • never log tokens.

---

14. Standard error envelope

All Auth API errors use the standard error envelope.

Example:

{
  "error": {
    "code": "auth.tokenExpired",
    "message": "The bearer token has expired.",
    "correlationId": "c3f1a8b2-4d6e-4f0a-9c1b-2e8d7a6b5c4d",
    "details": {}
  }
}

Partner-app behavior:

  • branch on error.code, not message;
  • log correlationId for support;
  • translate customer-facing messages in the partner UX;
  • follow endpoint-specific remediation guidance.

Common Auth API errors:

Error codeTypical meaningPartner-app action
auth.tokenExpiredAccess token expiredCall /v1/auth/refresh.
auth.tokenInvalidToken cannot be usedClear session and ask customer to log in.
auth.tokenRevokedToken was revokedClear session and ask customer to log in.
auth.credentialMismatchLogin credentials cannot be acceptedShow generic invalid-login message.
auth.loginAttemptExpiredLogin attempt expiredRestart login.
auth.registrationSessionExpiredRegistration session expiredRestart registration.
auth.otpInvalidOTP is incorrectAsk customer to retry, respecting attempts remaining if returned.
auth.otpExpiredOTP expiredRestart the OTP step.
auth.otpAttemptsExhaustedToo many OTP attemptsRestart the relevant flow or show support path.
validation.passwordPolicyViolationPassword does not meet policyShow password policy feedback.
device.registrationRequiredDevice not registeredStart device registration.
device.registrationChallengeExpiredDevice challenge expiredRestart device registration.
rate.limitedToo many requestsBack off and retry later.
internal.unavailableTemporary service problemShow retry message and preserve customer input where safe.

---

15. Implementation checklist

Before moving to Core API integration, confirm that the partner app can:

  • call /v1/auth/start;
  • call /v1/auth/login and handle all authStatus outcomes;
  • securely store and refresh tokens;
  • call /v1/auth/logout and clear local session state;
  • register a new customer;
  • complete OTP verification;
  • complete password reset;
  • list, add, and remove identifiers;
  • start and complete device registration;
  • handle token expiry and session loss;
  • log X-Correlation-Id and returned error.correlationId.

---

16. Related package documents

Use these next:

DocumentPurpose
03_Core_API_Guide.mdProfile, KYC, beneficiaries, quotes, transfers, funding, and transfer status.
04_End_to_End_Flows.mdFull customer journeys from registration to transfer completion.
05_Headers_Idempotency_Errors.mdCross-cutting request headers, idempotency, retries, and errors.
08_Device_Bound_Authentication.mdDetailed device key and JWS implementation guidance.
11_Sandbox_and_Testing_Guide.mdSandbox scenarios and expected test outcomes.