myTU PSD2 Open Banking API (XS2A)
The dedicated PSD2 access interface that myTU exposes under /psd2/v1 for
licensed Third-Party Providers - payment-initiation (PISP) and account-information (AISP) services.
Overview
This specification describes the dedicated PSD2 access interface (XS2A) that
myTU (Travel Union UAB, EMI permit No LB001966, Bank of Lithuania)
exposes under /psd2/v1, independent of the myTU Business API. It covers
two services: Payment Initiation (PIS) and Account Information (AIS).
Where practical the message shapes and status vocabulary follow the Berlin Group NextGenPSD2 convention, so a TPP that already integrates other European ASPSPs can reuse its tooling. myTU implements a pragmatic subset, documented in full here - if a field is not listed in these docs, do not rely on it.
Two services, one interface
- Payment Initiation (PIS) - start a payment, hand the payer an approval link, and learn the outcome by polling the status endpoint.
- Account Information (AIS) - with the customer's consent, read accounts, balances and transactions for up to 90 days.
Both services reuse the same authentication (QWAC + QSEAL) and the same in-app approval (SCA) through the customer's own myTU app.
# Base URL (sandbox)
https://psd2.mytu.dev/psd2/v1
# Authentication - no API keys
# · eIDAS QWAC → mutual TLS (the connection)
# · eIDAS QSEAL → request signing (the instruction)
# Payment Initiation (PIS)
POST /payments/{payment-product}
GET /payments/{payment-product}/{id}/status
DELETE /payments/{payment-product}/{id}
# Account Information (AIS)
POST /consents
GET /accounts
GET /accounts/{resourceId}/balances
GET /accounts/{resourceId}/transactions
Base URLs & versioning
All endpoints live under the /psd2/v1 prefix. Aggregators can use
https://psd2.mytu.live/psd2/v1 as the base URL; the paths beneath it
follow the Berlin Group relative layout.
| Environment | Base URL |
|---|---|
| Production | https://psd2.mytu.live |
| Sandbox | https://psd2.mytu.dev |
Integrate and test against the sandbox with your eIDAS test certificates; it
mirrors production behaviour. The interface is versioned by the /psd2/v1
path prefix - breaking changes ship under a new prefix.
/psd2/v1.
_links hrefs in responses use the same absolute form.POST https://psd2.mytu.live/psd2/v1\
/payments/sepa-credit-transfers
Conventions
These rules hold everywhere in the API. Read them once and they apply to every endpoint below.
| Topic | Rule |
|---|---|
| Paths | Absolute and always start with the /psd2/v1 prefix
(e.g. POST /psd2/v1/consents). |
| Monetary amounts | Decimal strings ("123.45"), never numbers. In
transactions a debit is negative, a credit is positive. |
| Currencies | ISO-4217 ("EUR"). |
| Dates & timestamps | Dates are ISO-8601 calendar dates ("2026-09-30"); timestamps are full
ISO-8601 ("2026-06-30T14:00:05Z"). |
| Ids | paymentId, consentId, resourceId are opaque
strings - never parse them. |
X-Request-ID |
A UUID required on every request and echoed on every response. |
eIDAS mutual TLS (QWAC)
There are no API keys, client secrets, or bearer tokens. A TPP authenticates by presenting a valid eIDAS QWAC certificate at the TLS handshake (mutual TLS).
- The certificate must carry an
organisationIdentifier(OID2.5.4.97) - the regulator-issued PSD2 authorisation number, e.g.PSDLT-BL-123456- and theclientAuthextended key usage. - The TPP's role (PISP / AISP) is taken from the certificate's PSD2 QcStatement. Calling a PIS endpoint requires the PISP role; an AIS endpoint requires the AISP role.
- The certificate identity establishes who the caller is. No further registration step is required.
curl https://psd2.mytu.dev/psd2/v1/accounts \
--cert qwac.pem \
--key qwac.key \
-H "X-Request-ID: 4f8e2c1a-..." \
-H "Consent-ID: a1b2c3d4e5f6..."
Request signing (QSEAL)
QWAC secures the connection. The payment-initiation POST
carries a money instruction, and the consent-creation POST carries an
access-authorization grant, so both must additionally be signed - their content is
then integrity-protected and non-repudiable. The TPP signs with its eIDAS QSEAL
(qualified electronic seal) certificate.
Three headers are required on the payment-initiation
POST and the consent-creation POST -
the requests that carry an instruction or a grant. Plain GET reads and
DELETE are not signed - they carry no instruction, and
nothing is read or executed without a valid consent or the customer's SCA.
| Header | Content |
|---|---|
Digest |
SHA-256=<base64> - hash of the raw request body. |
Signature |
The signature (HTTP Message Signatures form: keyId,
algorithm, headers, signature) covering at
least Digest, X-Request-ID, and the request target. |
TPP-Signature-Certificate |
The base64-encoded QSEAL certificate to verify against. |
What we verify
- The body hash matches
Digest. - The
Signaturevalidates against the QSEAL public key. - The QSEAL is a valid eIDAS seal certificate.
- It belongs to the same TPP as the QWAC (same
organisationIdentifier).
The verified signature is retained for audit / non-repudiation. A missing or invalid signature is
rejected (SIGNATURE_MISSING / SIGNATURE_INVALID).
Digest: SHA-256=47DEQpj8HBSa+/TImW+5JCeuQ...
Signature: keyId="...",
algorithm="...",
headers="digest x-request-id (request-target)",
signature="..."
TPP-Signature-Certificate: MIIE...QSEAL...==
How payment initiation works
myTU authorises payments through the customer's own myTU app - not through a web login on our side. The model is decoupled: you start a payment, we hand you back a link, the customer approves it inside the myTU app, and you learn the outcome by polling the status endpoint.
Initiate
TPP → POST /psd2/v1/payments/… → myTU returns a
paymentId + a link, status RCVD.
Hand off the approval link
Send the payer's browser to the link. On a phone it opens the myTU app directly; on a desktop the page shows a QR the payer scans with the myTU app.
Customer approves & signs
The payer approves and signs the payment inside the myTU app (SCA).
Poll for the outcome
TPP → GET …/status →
RCVD → ACSP → ACSC, or RJCT/CANC.
Key properties
- Every call is immediate. Requests return at once; there is no long-polling and no held-open connection. The wait for the human is covered by you polling the status.
- The payer identifies themselves by approving in their own app. You do not need to know which myTU customer they are.
debtorAccountis not required and is not used to route the request. If you send it, it is treated only as a constraint (the approving customer's account must match it) - it never determines who is asked to approve. Never assume that supplying an IBAN will prompt that account holder; it will not.
The approval link
The initiation response contains an scaRedirect link - a
myTU-hosted web page (served from the public host mytu.live,
or mytu.dev in the sandbox - not the psd2. API
host). You do not build a QR yourself. Just send the payer's browser to that link
(HTTP redirect, a button, or embed it in an iframe); the page adapts to the device:
- Mobile - the page opens the myTU app directly on the payment-approval screen. No scanning needed.
- Desktop - the page itself renders a QR code for the payer to
scan with their myTU app. You can poll the status endpoint alongside it and update your page when
the payment becomes final. If you supplied
TPP-Redirect-URI, the customer is returned there after approval.
scaRedirect link as-is;
do not generate your own QR from it.The link is single-use: once the payment is approved, cancelled, or expired, opening it again only shows the final state.
Lifetime
An initiated-but-unapproved payment expires after roughly 5 minutes of inactivity -
the window refreshes when the customer opens the approval link and stays alive while they are
actively approving, so a customer mid-signature is never cut off. After expiry the status becomes
RJCT. The paymentId and its status remain
queryable after expiry and after settlement.
1. TPP POST /psd2/v1/payments/…
→ paymentId + link (RCVD)
2. TPP send payer's browser → link
• phone → opens myTU app
• desktop → page shows a QR
3. payer approves & signs in app
4. TPP GET …/status (poll)
RCVD → ACSP → ACSC
or → RJCT / CANC
Initiate a payment
{payment-product} is one of:
| Product | Meaning |
|---|---|
sepa-credit-transfers | Standard SEPA credit transfer (EUR). |
instant-sepa-credit-transfers | SEPA Instant credit transfer (EUR). |
Instant vs regular
sepa-credit-transfersis best-effort instant - we execute over the SCT Inst rail whenever the beneficiary bank is reachable and the amount qualifies, otherwise as a normal SCT. The customer simply gets it faster when possible; never rejected for instant being unavailable.instant-sepa-credit-transfersis enforced - if the beneficiary bank is not reachable for SCT Inst, or the amount exceeds the instant cap, the request is rejected (400PRODUCT_INVALID); it is never silently downgraded to a regular transfer. Availability is checked at initiation (early reject) and again enforced at execution.
Headers
| Header | Req. | Notes |
|---|---|---|
X-Request-ID |
yes | UUID; echoed back on every response. Idempotency key (1-hour window):
retrying with the same X-Request-ID and the same body
replays the original 201; the same
X-Request-ID with a different body is rejected
409 REQUEST_ID_REUSE. |
Digest | yes | SHA-256=<base64> of the body - see Request signing. |
Signature | yes | QSEAL signature over Digest + X-Request-ID + target. |
TPP-Signature-Certificate | yes | base64 QSEAL certificate. |
TPP-Redirect-URI | no | Where to return the customer's browser after approval. |
PSU-IP-Address | no | The payer's IP, when the payer is present in your flow. |
Content-Type | yes | application/json |
Request body
amountis a decimal string.creditorAccount.ibanandcreditorNameare required.remittanceInformationUnstructuredis optional, max 140 characters.debtorAccount({ "iban": "…" }) is optional and not used for routing.
Deliver _links.scaRedirect.href to the payer as described in
How payment initiation works.
curl -X POST \
https://psd2.mytu.dev/psd2/v1/payments/sepa-credit-transfers \
--cert qwac.pem --key qwac.key \
-H "X-Request-ID: 4f8e2c1a-9b7d-4f0e-8a2b-1c3d4e5f6071" \
-H "Content-Type: application/json" \
-H "Digest: SHA-256=47DEQpj8HBSa+/TImW+5JCeuQ..." \
-H 'Signature: keyId="...",algorithm="...",headers="digest x-request-id (request-target)",signature="..."' \
-H "TPP-Signature-Certificate: MIIE...==" \
-d '{
"instructedAmount": { "currency": "EUR", "amount": "123.45" },
"creditorAccount": { "iban": "LT121000011101001000" },
"creditorName": "Merchant Ltd",
"remittanceInformationUnstructured": "Invoice 12345"
}'
{
"instructedAmount": { "currency": "EUR", "amount": "123.45" },
"creditorAccount": { "iban": "LT121000011101001000" },
"creditorName": "Merchant Ltd",
"remittanceInformationUnstructured": "Invoice 12345"
}
{
"transactionStatus": "RCVD",
"paymentId": "b3f1c2a4e5d647809a1b2c3d4e5f6071",
"_links": {
"scaRedirect": {
"href": "https://mytu.live/sca.pi.html?p=b3f1c2a4e5d647809a1b2c3d4e5f6071"
},
"status": {
"href": "/psd2/v1/payments/sepa-credit-transfers/b3f1c2a4e5d647809a1b2c3d4e5f6071/status"
},
"self": {
"href": "/psd2/v1/payments/sepa-credit-transfers/b3f1c2a4e5d647809a1b2c3d4e5f6071"
}
}
}
transactionStatus: "RCVD".Get payment status
Poll this until a final status. A reasonable cadence is every 2-5 seconds while the customer is approving.
RJCT/CANC
as terminal failures and ACSC as success.curl https://psd2.mytu.dev/psd2/v1\
/payments/sepa-credit-transfers\
/b3f1c2a4e5d647809a1b2c3d4e5f6071/status \
--cert qwac.pem --key qwac.key \
-H "X-Request-ID: 7a2b1c3d-..."
{ "transactionStatus": "ACSP" }
Get payment details
Returns the submitted payment data plus the current transactionStatus.
curl https://psd2.mytu.dev/psd2/v1\
/payments/sepa-credit-transfers\
/b3f1c2a4e5d647809a1b2c3d4e5f6071 \
--cert qwac.pem --key qwac.key \
-H "X-Request-ID: 5e9d8c7b-..."
{
"transactionStatus": "ACSC",
"paymentId": "b3f1c2a4e5d647809a1b2c3d4e5f6071",
"instructedAmount": { "currency": "EUR", "amount": "123.45" },
"creditorAccount": { "iban": "LT121000011101001000" },
"creditorName": "Merchant Ltd",
"remittanceInformationUnstructured": "Invoice 12345"
}
Cancel a payment
Cancels a payment before the customer has started approval. The response returns
transactionStatus: "CANC". Once the customer has opened the payment in the
app, or the payment is already final, it can no longer be cancelled
(409).
After cancellation the payment is terminated; a subsequent status poll reports it as a terminal
failure (RJCT) - you already have the authoritative
CANC from this response.
curl -X DELETE \
https://psd2.mytu.dev/psd2/v1\
/payments/sepa-credit-transfers\
/b3f1c2a4e5d647809a1b2c3d4e5f6071 \
--cert qwac.pem --key qwac.key \
-H "X-Request-ID: 9f1e2d3c-..."
{ "transactionStatus": "CANC" }
Payment status values
The transactionStatus field moves through these codes.
| Code | Meaning | Final? |
|---|---|---|
RCVD | Received - initiated, awaiting customer approval. | no |
ACTC | Accepted Technical Validation - approval in progress. | no |
ACSP | Accepted Settlement in Process - customer approved, executing. | no |
ACSC | Accepted Settlement Completed. | yes · success |
RJCT | Rejected - declined, failed, or expired. | yes · failure |
CANC | Cancelled by the TPP - returned by the DELETE response (a later status poll reports RJCT). | yes · failure |
How account access works
AIS lets an authorised AISP read a customer's myTU account data - accounts, balances, transactions - with the customer's consent. The model is consent-based and decoupled, and reuses the same authentication (QWAC + QSEAL) and the same in-app approval (the scan/SCA link) as PIS. The shape is different from a payment, though: a payment is one-shot; a consent is a standing grant the AISP reuses for up to 90 days.
Create a consent
TPP → POST /psd2/v1/consents → myTU returns a
consentId + a link, status received.
Hand off the approval link
Send the customer's browser to the link - phone opens the myTU app on the consent screen; desktop shows a QR to scan.
Customer approves (SCA)
The customer reviews the requested access & approves in the myTU app → consent
valid.
Read account data
TPP reads account data carrying the Consent-ID header,
repeatedly within the validity.
Key properties
- A consent is a standing grant. Once
valid, the AISP reuses it (no fresh approval per call) for up to itsvalidUntil, which myTU caps at 90 days. - “Customer present” vs “unattended.” When the customer is in the loop, send the
PSU-IP-Addressheader - that access is unlimited. Unattended polling (noPSU-IP-Address) is limited tofrequencyPerDayretrievals. - The customer identifies themselves by approving. As with PIS, you do not need to know which myTU customer they are; the consent binds to whoever approves it.
- The customer chooses which account at approval - their personal
account or a business they represent - so a consent is bound to one account
(which may be a company). If you named a specific IBAN in
access, the customer must select a matching account; withallPsd2/availableAccountsthey choose freely. - You never deal with the IBAN as an id.
GET /psd2/v1/accountsreturns an opaqueresourceId; use that in the balance/transaction calls.
# consent - addressed by id in the PATH
POST /psd2/v1/consents (QSEAL)
GET /psd2/v1/consents/{id}
GET /psd2/v1/consents/{id}/status
DELETE /psd2/v1/consents/{id}
# account data - Consent-ID HEADER required
GET /psd2/v1/accounts
GET /psd2/v1/accounts/{resourceId}/balances
GET /psd2/v1/accounts/{resourceId}/transactions
valid.Create a consent
Signed with QSEAL - same three headers as a payment initiation. Also requires
X-Request-ID (echoed; idempotent) and
Content-Type: application/json;
TPP-Redirect-URI and PSU-IP-Address are
optional.
Body fields
| Field | Description |
|---|---|
access |
What may be read. Either explicit lists of { iban } under
balances and/or transactions, or a wildcard
"allPsd2": "allAccounts" (full access to all the customer's accounts) /
"availableAccounts": "allAccounts" (list accounts only, no
balances/transactions). |
recurringIndicator |
true = reusable standing consent; false = one-off (single
retrieval). |
validUntil |
Requested expiry (date). myTU caps it at 90 days and may return a shorter value. |
frequencyPerDay |
Max unattended retrievals per day (≥ 1; for a one-off,
1). |
Deliver _links.scaRedirect.href to the customer exactly as for PIS. The
consent becomes valid once they approve it in the app.
{
"access": {
"balances": [ { "iban": "LT121000011101001000" } ],
"transactions": [ { "iban": "LT121000011101001000" } ]
},
"recurringIndicator": true,
"validUntil": "2026-09-30",
"frequencyPerDay": 4,
"combinedServiceIndicator": false
}
{
"consentStatus": "received",
"consentId": "a1b2c3d4e5f6...",
"_links": {
"scaRedirect": {
"href": "https://mytu.live/sca.ai.html?c=a1b2c3d4e5f6..."
},
"status": { "href": "/psd2/v1/consents/a1b2c3d4e5f6.../status" },
"self": { "href": "/psd2/v1/consents/a1b2c3d4e5f6..." }
}
}
"access": { "allPsd2": "allAccounts" } for full
access, or "availableAccounts": "allAccounts" to list accounts only.Manage a consent
Read, check the status of, or revoke a consent. These calls address the consent by id in the path and are not QSEAL-signed.
Returns the access object, recurringIndicator,
validUntil, frequencyPerDay,
consentStatus, and lastActionDate.
Returns just { "consentStatus": "valid" }.
Revokes the consent; consentStatus becomes
terminatedByTpp.
DELETE revokes the consent immediately and irreversibly; from that
point every account-data call fails. Revoking an already-terminal consent (expired or already
revoked) returns 409.A consent can also reach a terminal state without your action -
revokedByPsu (the customer revoked it in the myTU app) or
expired. Treat every terminal consentStatus as
final and stop calling; re-check with GET …/status if a data call starts
returning 401/403.
{
"consentStatus": "valid",
"access": {
"balances": [ { "iban": "LT121000011101001000" } ],
"transactions": [ { "iban": "LT121000011101001000" } ]
},
"recurringIndicator": true,
"validUntil": "2026-09-30",
"frequencyPerDay": 4,
"lastActionDate": "2026-06-30"
}
{ "consentStatus": "valid" }
{ "consentStatus": "terminatedByTpp" }
List accounts
Header Consent-ID (required) + the QWAC. Returns the accounts the consent
grants. This is the entry point of every retrieval - call it first to obtain each account's
resourceId, then use that id in the balance/transaction calls. A
resourceId is stable for the life of the consent, so you
may store it.
?withBalance=true embeds balances inline (only if the consent grants
balances); an availableAccounts-only consent
lists accounts but never balances or transactions.
resourceId (not the IBAN) in the calls below.curl https://psd2.mytu.dev/psd2/v1/accounts \
--cert qwac.pem --key qwac.key \
-H "X-Request-ID: 1a2b3c4d-..." \
-H "Consent-ID: a1b2c3d4e5f6..."
{
"accounts": [
{
"resourceId": "0fa3...",
"iban": "LT121000011101001000",
"currency": "EUR",
"name": "ACME UAB",
"ownerName": "ACME UAB",
"balances": [ /* present only with ?withBalance=true */ ]
}
]
}
Balances
Header Consent-ID. Requires the consent's access
to cover balances for this account. A myTU account is multi-currency, so
balances[] carries one entry per currency held;
balanceType is interimAvailable (spendable now).
curl https://psd2.mytu.dev/psd2/v1\
/accounts/0fa3.../balances \
--cert qwac.pem --key qwac.key \
-H "X-Request-ID: 2b3c4d5e-..." \
-H "Consent-ID: a1b2c3d4e5f6..."
{
"account": { "iban": "LT121000011101001000" },
"balances": [
{
"balanceType": "interimAvailable",
"balanceAmount": { "currency": "EUR", "amount": "1234.56" }
},
{
"balanceType": "interimAvailable",
"balanceAmount": { "currency": "USD", "amount": "0.00" }
}
]
}
Transactions
Header Consent-ID. Requires the consent's
access to cover transactions for this account.
Query parameters
| Param | Description |
|---|---|
dateFrom req | ISO date; start of the window. |
dateTo opt | ISO date, defaults to today; inclusive. |
bookingStatus opt |
booked (default), pending, or both.
|
transactionAmount.amountis signed: debits negative, credits positive (always EUR - the amount that moved on the account; a cross-border transfer shows the EUR charged, not the destination currency).- If the response includes
transactions._links.next, follow it for the next page; its absence means the set is complete. Narrow the date window for very large histories.
curl "https://psd2.mytu.dev/psd2/v1\
/accounts/0fa3.../transactions\
?dateFrom=2026-06-01&dateTo=2026-06-30\
&bookingStatus=booked" \
--cert qwac.pem --key qwac.key \
-H "X-Request-ID: 3c4d5e6f-..." \
-H "Consent-ID: a1b2c3d4e5f6..."
{
"account": { "iban": "LT121000011101001000" },
"transactions": {
"booked": [
{
"transactionId": "...",
"bookingDate": "2026-06-14",
"valueDate": "2026-06-14",
"transactionAmount": { "currency": "EUR", "amount": "-42.00" },
"creditorName": "Merchant Ltd",
"remittanceInformationUnstructured": "Invoice 12345"
}
],
"pending": []
}
}
Consent status values
| Code | Meaning | Final? |
|---|---|---|
received | Created, awaiting customer approval (SCA). | no |
valid | Approved - account-data calls are allowed. | no |
expired | Past validUntil. | yes |
revokedByPsu | The customer revoked it in the app. | yes |
terminatedByTpp | The TPP revoked it via DELETE. | yes |
rejected | The customer declined the approval. | yes |
Access limits
- Validity - up to 90 days
(
validUntil); after that the AISP must obtain a new consent. - Frequency -
frequencyPerDaycaps unattended retrievals per day. SendPSU-IP-Addresswhen the customer is present to access without counting against the cap. Over the cap → 429ACCESS_EXCEEDED. - One “retrieval” is a logical access (the set of calls to assemble a view), not each individual
GET.
Errors
Every error returns the appropriate HTTP status with a Berlin Group
tppMessages body.
{
"tppMessages": [
{
"category": "ERROR",
"code": "FORMAT_ERROR",
"text": "creditorAccount.iban is required"
}
]
}
category is always ERROR;
text is a human-readable detail -
branch on code + HTTP status, not on
text. The complete set of codes:
| Code | HTTP | When |
|---|---|---|
FORMAT_ERROR | 400 | Malformed JSON, or a missing / invalid field. |
PRODUCT_INVALID | 400 | instant-sepa-credit-transfers not possible for this beneficiary or amount. |
SIGNATURE_MISSING | 400 | A required QSEAL header (Digest / Signature / TPP-Signature-Certificate) is absent. |
CERTIFICATE_MISSING | 401 | No client certificate presented at the TLS handshake. |
CERTIFICATE_INVALID | 401 | Not a valid eIDAS QWAC, or a missing / mismatched organisationIdentifier. |
SIGNATURE_INVALID | 401 | The QSEAL signature does not verify, or does not cover the required headers. |
CONSENT_INVALID | 401 / 403 | Consent unknown, not yet approved, revoked, owned by another TPP, or does not cover the requested account / data. |
CONSENT_EXPIRED | 401 | Consent is past its validUntil. |
ROLE_INVALID | 403 | The certificate lacks the required role (PISP for payments, AISP for AIS). |
RESOURCE_UNKNOWN | 404 | Unknown paymentId, account resource, or path. |
CONSENT_UNKNOWN | 404 | Unknown consentId. |
PRODUCT_UNKNOWN | 405 | Unsupported {payment-product}. |
REQUEST_ID_REUSE | 409 | X-Request-ID reused with a different body. |
CANCELLATION_INVALID | 409 | The payment can no longer be cancelled (approval started, or already final). |
ACCESS_EXCEEDED | 429 | The consent's frequencyPerDay for unattended access was reached. |
INTERNAL_SERVER_ERROR | 500 | Unexpected server error - safe to retry later. |
tppMessages) may also be
returned by overall rate limiting; back off and retry.Status callbacks
By default you poll the status endpoint. On request, myTU can additionally push a signed notification to a URL you register, on each status change, so you do not have to poll aggressively. Polling remains the source of truth.
# default - you poll (the source of truth)
GET /psd2/v1/payments/.../status
# optional - myTU pushes a signed notification
# on each status change to a URL you register
your-tpp.example/psd2-callback
Out of scope for v1
The following are not part of this version and must not be relied on:
- Bulk payments, periodic / standing-order payments, future-dated payments.
- Funds confirmation (PIIS / CBPII).
- Card-account access (
/psd2/v1/card-accounts). - Transactions as a downloadable
camt.053file (JSON only).
Any of these may be added in a future version under the same interface and authentication model.