Skip to main content
ΕΛ

API DOCUMENTATION

Partner API

The Partner API lets a partner create my-data.app accounts for its merchants, check whether an email already exists, and read each registration status. It is a server-to-server API authenticated with a bearer key.

Download openapi.json The OpenAPI 3.1 document is generated from the same contract and covers every endpoint, schema, scope and error code.

Quick start

Five steps from reading the requirements to the registration status.

  1. Read the requirementsCall GET /requirements with the requirements:read scope for the current legal version, documents, scopes and limits.
  2. Check the emailCall POST /users/check with the users:check scope to see whether the merchant needs a new account or linking.
  3. Create the registrationCall POST /registrations with the registrations:write scope, sending an Idempotency-Key and acceptance of the current legal version.
  4. Complete linking or automatic sign-inFor an existing email hand the merchant the linking_url. For a new account with automatic mode, the automatic_sign_in_url may be used instead.
  5. Follow the statusCall GET /registrations/{registration_id} with the registrations:read scope until the status is ready.

Base URLs per deployment

Production
https://my-data.app/api/partners/v1
Sandbox
https://sandbox.my-data.app/api/partners/v1
Local development
http://localhost:4321/api/partners/v1

Authentication and scopes

Every request sends Authorization: Bearer with the partner key. Keys are created and rotated by the my-data.app administrator, shown once, and revoked immediately on rotation.

Scopes

requirements:read
Read the current legal version, documents, scopes and limits.
users:check
Check whether an email already owns a my-data.app account.
registrations:write
Create a merchant registration or a linking request.
registrations:read
Read the status of a registration owned by the same partner.

Partner capabilities

verified_email
Allows accepting the verified_email field. Without it, registrations are refused with partner_capability_required.
legal_acceptance
Allows accepting the current legal version on the merchant's behalf.
automatic_login
Allows login_mode: automatic and issuing automatic_sign_in_url for new accounts.

Limits

Requests per key
60 per minute
Body size
16 KiB JSON
Automatic sign-in life
5 minutes, issued within 10 minutes
Linking link life
15 minutes

Requirements and legal version

GET/api/partners/v1/requirements

Scope: requirements:read

Returns the current legal version, the legal documents the merchant must accept, the available scopes and the limits.

cURL example

curl -sS \
  "$MY_DATA_BASE_URL/requirements" \
  -H "Authorization: Bearer $MY_DATA_PARTNER_KEY"

Responses

  • 200Success
  • 401 / 403Invalid key or missing scope
  • 405Unsupported method. Use the method defined for the endpoint.
  • 429Rate limit exceeded. Check the Retry-After header.
  • 503Temporarily unavailable

Response example

Success

{
  "legal_version": "2026-07-12",
  "legal_documents": {
    "terms": "https://my-data.app/terms",
    "privacy": "https://my-data.app/privacy",
    "data_processing_addendum": "https://my-data.app/data-processing-addendum"
  },
  "scopes": [
    "requirements:read",
    "users:check",
    "registrations:write",
    "registrations:read"
  ],
  "limits": {
    "bodyBytes": 16384,
    "requestsPerMinute": 60,
    "loginSeconds": 300,
    "loginWindowSeconds": 600,
    "linkSeconds": 900,
    "leaseSeconds": 120
  }
}

The returned legal_version is sent in the registration legal_acceptance.version. Accepting an older version is refused with legal_version_outdated.

Email check

POST/api/partners/v1/users/check

Scope: users:check

Checks whether the email already owns a my-data.app account and whether a registration already exists for this partner.

Request body

{
  "email": "merchant@example.com"
}

cURL example

curl -sS \
  "$MY_DATA_BASE_URL/users/check" \
  -H "Authorization: Bearer $MY_DATA_PARTNER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email":"merchant@example.com"}'

Responses

  • 200Success
  • 400Invalid data
  • 401 / 403Invalid key or missing scope
  • 405Unsupported method. Use the method defined for the endpoint.
  • 429 / 503Rate limit exceeded. Check the Retry-After header. / Temporarily unavailable

Response example

Success

{
  "exists": true,
  "registration": {
    "registration_id": "pr_00000000-0000-4000-8000-000000000000",
    "status": "ready"
  }
}

Success

{
  "exists": false,
  "registration": null
}

Read-only. It never creates or changes an account. Use it to choose between a new account and linking.

Create registration

POST/api/partners/v1/registrations

Scope: registrations:write

Creates an account for a new email or a linking request for an existing email. The same email and password are used only when the email is new.

Request body

{
  "customer_id": "customer_123",
  "email": "merchant@example.com",
  "password": "EXAMPLE_PASSWORD_REPLACE_ME",
  "locale": "en",
  "login_mode": "password",
  "verified_email": {
    "verified_at": "2026-10-01T10:00:00Z",
    "reference": "verification_123"
  },
  "legal_acceptance": {
    "version": "2026-07-12",
    "accepted_at": "2026-10-01T10:01:00Z",
    "reference": "consent_123"
  }
}

cURL example

curl -sS \
  "$MY_DATA_BASE_URL/registrations" \
  -H "Authorization: Bearer $MY_DATA_PARTNER_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: idem_example_7c4a1d" \
  -d @registration.json

Responses

  • 201Registration created
  • 200Idempotent replay of the same Idempotency-Key
  • 400 / 422Invalid data / Password or account fields rejected
  • 405Unsupported method. Use the method defined for the endpoint.
  • 409Identity conflict, registration busy or outdated legal version
  • 429 / 503Rate limit exceeded. Check the Retry-After header. / Temporarily unavailable

Response example

Ready with password sign-in

{
  "registration_id": "pr_00000000-0000-4000-8000-000000000000",
  "sign_in_url": "https://my-data.app/sign-in?lang=en",
  "status": "ready"
}

Ready with automatic sign-in

{
  "registration_id": "pr_00000000-0000-4000-8000-000000000000",
  "sign_in_url": "https://my-data.app/sign-in?lang=en",
  "status": "ready",
  "automatic_sign_in_url": "https://my-data.app/connect/partner#ticket=EXAMPLE_TICKET",
  "expires_at": "2026-10-01T10:06:00Z"
}

Linking required

{
  "registration_id": "pr_00000000-0000-4000-8000-000000000000",
  "sign_in_url": "https://my-data.app/sign-in?lang=en",
  "status": "linking_required",
  "linking_url": "https://my-data.app/connect/partner#link=EXAMPLE_LINK",
  "expires_at": "2026-10-01T10:16:00Z"
}

First use provisions the normal workspace in Test with the trial, with no billing or provider connection.

For an existing email, linking_url is returned and the merchant completes linking consent. The password is not changed, and the request gains no account access without that consent.

With login_mode automatic and the automatic_login capability enabled, a single-use automatic_sign_in_url with a five-minute life is returned, issued within ten minutes of completion.

Registration status

GET/api/partners/v1/registrations/{registration_id}

Scope: registrations:read

Returns only the identifier, the status and the normal sign_in_url for a registration owned by the same partner.

cURL example

curl -sS \
  "$MY_DATA_BASE_URL/registrations/pr_00000000-0000-4000-8000-000000000000" \
  -H "Authorization: Bearer $MY_DATA_PARTNER_KEY"

Responses

  • 200Success
  • 401 / 403Invalid key or missing scope
  • 404Unknown registration for this partner
  • 405Unsupported method. Use the method defined for the endpoint.
  • 429 / 503Rate limit exceeded. Check the Retry-After header. / Temporarily unavailable

Response example

Success

{
  "registration_id": "pr_00000000-0000-4000-8000-000000000000",
  "status": "processing",
  "sign_in_url": "https://my-data.app/sign-in?lang=en"
}

Linking and automatic sign-in URLs are never returned by this endpoint. Repeat the request until the status is ready.

Recover a registration or linking URL

POST/api/partners/v1/registrations

Scope: registrations:write

After an error or recoverable_failure, replay the same request to reconcile that registration. If status is linking_required and the linking_url was lost or expired, replay POST /registrations with the same Idempotency-Key and body to receive a replacement link.

Request body

{
  "customer_id": "customer_123",
  "email": "merchant@example.com",
  "password": "EXAMPLE_PASSWORD_REPLACE_ME",
  "locale": "en",
  "login_mode": "password",
  "verified_email": {
    "verified_at": "2026-10-01T10:00:00Z",
    "reference": "verification_123"
  },
  "legal_acceptance": {
    "version": "2026-07-12",
    "accepted_at": "2026-10-01T10:01:00Z",
    "reference": "consent_123"
  }
}

cURL example

curl -sS \
  "$MY_DATA_BASE_URL/registrations" \
  -H "Authorization: Bearer $MY_DATA_PARTNER_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: idem_example_7c4a1d" \
  -d @registration.json

Responses

  • 200Idempotent replay of the same Idempotency-Key
  • 201Registration created
  • 405Unsupported method. Use the method defined for the endpoint.
  • 409Identity conflict, registration busy or outdated legal version
  • 503Temporarily unavailable

Response example

503

{
  "error": {
    "code": "identity_unavailable",
    "message": "The identity service is unavailable. Retry with the same key."
  }
}

Keep the same key and body. A 503 may represent unconfirmed identity creation; replay reconciles that attempt and never blindly creates another account. The status GET does not return a replacement linking_url.

Registration fields

customer_id
Your own customer identifier. Reused to detect duplicates across retries.
email
The merchant email. The /users/check result decides a new account or linking.
password
Required only for a new email. Omit for existing accounts or completed replays. It is never stored and never changes an existing password.
locale
el or en for the merchant language.
first_name / last_name
Optional. Used when the account is created.
login_mode
password (default) or automatic for new accounts.
verified_email
Object with verified_at (ISO 8601) and reference. Declares the email verified by the partner. Future timestamps are allowed up to 60 seconds.
legal_acceptance
Object with version (the current legal_version), accepted_at and reference. The acceptance is stored as evidence.

Statuses

processing
The registration is being processed. Retry with the same Idempotency-Key.
ready
The registration is complete. The merchant signs in with sign_in_url.
linking_required
The email already exists. Linking through linking_url is required.
recoverable_failure
The attempt did not complete. Submit the registration again with the same key.

Error codes

invalid_partner_key
The bearer key is missing, unknown or revoked.
partner_scope_required
The key does not carry the required scope.
partner_capability_required
The partner does not have the required capability enabled.
rate_limited
The key exceeded the limit of 60 requests per minute.
invalid_json
The body is not a valid JSON object with Content-Type application/json.
invalid_input
A field is missing or invalid.
payload_too_large
The body is larger than 16 KiB.
legal_version_outdated
The legal version is not current. Read the requirements again.
idempotency_conflict
The same Idempotency-Key was reused with different data.
registration_busy
The registration is currently being processed. Retry with the same key.
registration_not_found
No such registration exists for the partner.
identity_conflict
The email or customer identity conflicts with a different existing identity.
password_rejected
The identity provider rejected the password or account fields.
identity_unavailable
The identity service is unavailable. Retry with the same key.
login_window_expired
The automatic sign-in window expired. Use sign_in_url.
login_unavailable
Automatic sign-in could not be issued. Use sign_in_url.
link_invalid
The linking link expired or is not valid.
link_email_mismatch
Linking requires the email that owns this registration.
auth_required
Authentication is required for this action.
invalid_origin
HTTPS is required outside local development; browser linking requests must have the same origin.
method_not_allowed
The method is not supported for this endpoint.
not_found
The endpoint or identifier was not found.
partner_unavailable
The partner service is unavailable. Retry later.