From b4736832254728b1bf0a9cffff8c09b7b78a2e63 Mon Sep 17 00:00:00 2001 From: Illan Colombick Date: Tue, 20 Oct 2026 19:34:07 +1300 Subject: [PATCH] fix(bankfeeds): Describe V2 partial failures so apps can branch on error.type - Replace the four partial-failure types with five that each fix one recovery action: partial-failure-new-account-creation, partial-failure-new-account-existence-not-confirmed, partial-failure-previous-connection-deletion, partial-failure-connection-creation and partial-failure-connection-deletion - Add optional subtype, and accountId, accountName and connectionId on the error, so apps don't need to read title or detail - Item errors have no status property; the item's statusCode is the number (new ItemError schema) - Describe item-level internal-error (REJECTED, 500) and the 207 Multi-Status response Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- xero_bankfeeds_v2.yaml | 469 ++++++++++++++++++++++++++++++----------- 1 file changed, 344 insertions(+), 125 deletions(-) diff --git a/xero_bankfeeds_v2.yaml b/xero_bankfeeds_v2.yaml index 909b14ab3..68fd48183 100644 --- a/xero_bankfeeds_v2.yaml +++ b/xero_bankfeeds_v2.yaml @@ -1,11 +1,33 @@ openapi: 3.0.0 info: - version: 19.1.0 + version: 2.0.0 title: Xero Bank Feeds API v2 description: >- - The Bank Feeds API is available to financial institutions with a Xero partnership and approved app partners. For non-bank apps, it automates statement imports into Xero bank and credit card accounts; it does not create a direct bank feed. - - Feed Connections 2.0 is intended to replace 1.0. The customer chooses whether to connect an existing Xero account or create a new one. Use ExistingAccount with the chosen accountId, or NewAccount to create an account; Xero does not guess which account to connect or silently change an account name. The GET and delete operations also use 2.0. Statements continue to use 1.0. + The Bank Feeds API is available to financial institutions with a Xero partnership and + approved app partners. For non-bank apps, it automates statement imports into Xero bank + and credit card accounts; it does not create a direct bank feed. + + Feed Connections 2.0 is intended to replace 1.0. The customer chooses + whether to connect an existing Xero account or create a new one. Use ExistingAccount with + the chosen accountId, or NewAccount to create an account; Xero does not guess which + account to connect or silently change an account name. The GET and delete operations + also use 2.0. Statements continue to use 1.0. + + Partial failures are rare, and nearly all are recoverable by your app with no need to contact + Xero support. If an item in a write response has `status` `PARTIAL_FAILURE`, handle only that + item and read its `error.type`. For `partial-failure-new-account-creation`, do not resend the + NewAccount item: connect `error.accountId` with `POST /FeedConnections/ExistingAccount`. For + `partial-failure-new-account-existence-not-confirmed`, the account named in `error.accountName` + may or may not exist. Use the Accounting API to check whether an account with that name exists. + If it does, connect it with `POST /FeedConnections/ExistingAccount`. If it does not, resend the + NewAccount item. If your app has a user, you can show them this message instead: "Something went + wrong. Please check whether your chosen account name now exists. If it does, connect it. If not, + try creating the new one again." For any + other `partial-failure-*` type, resend the same item. If a create recovery returns 409 + `feed-already-connected-in-current-organisation`, the earlier attempt succeeded: treat the item + as created and use `GET /FeedConnections` to find its `id`. `error.subtype` is optional + diagnostics; do not branch on it, and never parse `title` or `detail`. Full detail: + https://developer.xero.com/documentation/api/bankfeeds/feedconnections-2-0-errors/#partial-failures termsOfService: https://developer.xero.com/xero-developer-platform-terms-conditions/ contact: name: Xero Platform Team @@ -33,7 +55,7 @@ paths: A `page` beyond the end of the collection returns an empty `items` array rather than an error. -' + ' parameters: - $ref: '#/components/parameters/XeroTenantId' - name: page @@ -85,9 +107,9 @@ paths: is not a GUID at all. These cases are deliberately indistinguishable from one another, so an - Application cannot use this endpoint to discover what another Application holds. + Application cannot use this endpoint to discover what another Application has. -' + ' parameters: - name: id in: path @@ -133,11 +155,11 @@ paths: operationId: createFeedConnectionsForExistingAccounts summary: Connect feeds to Xero Bank Accounts that already exist externalDocs: - description: Partial-failure recovery by error title + description: Partial-failure recovery by error type url: https://developer.xero.com/documentation/api/bankfeeds/feedconnections-2-0-errors/#partial-failures - description: 'Creates Feed Connections against Xero Bank Accounts the Organisation already holds. Every + description: 'Creates Feed Connections against Xero Bank Accounts the Organisation already has. Each - item must carry the `accountId` of the account it connects to. Xero performs no matching of + item must include the `accountId` of the account it connects to. Xero performs no matching of its own, and `accountNumber` and `accountName` are ignored if supplied. @@ -147,11 +169,11 @@ paths: reconnecting a feed that was previously terminated. - Each item is processed independently, and the response carries one result per request item in + Each item is processed independently, and the response has one result per request item in request order. -' + ' parameters: - $ref: '#/components/parameters/XeroTenantId' requestBody: @@ -173,16 +195,16 @@ paths: country: GB responses: '200': - description: 'Every item is 2xx: each one reached its desired state and nothing is left for you to + description: 'All items are 2xx: each one reached its desired state, and there is nothing left for you - do. A created item carries `status` `SUCCESS` and `statusCode` `201`. + to do. A created item has `status` `SUCCESS` and `statusCode` `201`. A response that mixes successful items with rejected or partially failed ones is a `207`, not a `200`. -' + ' content: application/json: schema: @@ -198,14 +220,17 @@ paths: status: SUCCESS statusCode: 201 '207': - description: 'Some items did not reach their desired state. Every item has its own result, so read + description: 'Some items did not reach their desired state. Each item has its own result, so read the `items` array rather than the envelope. - `207` means the item codes were neither all 2xx nor all 4xx. A `PARTIAL_FAILURE` item carries `statusCode` `500`. On this endpoint, it can be `partial-failure-migration-can-be-reattempted` (three titles) or `partial-failure-connection-created-but-not-recorded` (one title). Some cases allow resending the same item; others require checking the account first. Match `error.type` and `error.title`, then follow the recovery table at https://developer.xero.com/documentation/api/bankfeeds/feedconnections-2-0-errors/#partial-failures . + Partial failures are rare, and nearly all are recoverable by your app. On this endpoint a partial failure is `partial-failure-previous-connection-deletion` or `partial-failure-connection-creation`: resend the same item. `error.accountId` and `error.connectionId` identify the account and connection; `error.subtype` is optional diagnostics. If the resend returns 409 `feed-already-connected-in-current-organisation`, the earlier attempt was recorded: treat the item as created. A connection an earlier attempt left in Xero without a feed connection never causes that 409: the resend replaces it. See https://developer.xero.com/documentation/api/bankfeeds/feedconnections-2-0-errors/#partial-failures . + -' + `207` means the item codes were neither all 2xx nor all 4xx. A `PARTIAL_FAILURE` item has `statusCode` `500`: the item did not complete, and the state it left behind needs attention or could not be confirmed. `error.subtype` says which. A `REJECTED` item whose error is `internal-error` also has `statusCode` `500`, so it makes the response a `207` (as does a batch in which all items are like that): something unexpected went wrong for that item, and nothing was written or a write could not be confirmed, so resending the item is safe. + + ' content: application/json: schema: @@ -222,27 +247,26 @@ paths: error: type: account-not-valid title: Invalid Account - status: 422 detail: The account specified in the request is not valid. - accountToken: '10000125' status: PARTIAL_FAILURE statusCode: 500 error: - type: partial-failure-migration-can-be-reattempted - title: Migration Incomplete, Replacement Not Created - status: 500 - detail: The account migration is only partially complete. The previous connection '880600c2-d302-4b9c-a88a-e0253c926ab2' on Xero bank account '9f2b1c44-7a0e-4d6e-b2d1-3c8e5a7f0b11' was removed and the replacement was not created, so the account now has no feed. Reattempt the create operation. If a reattempt keeps reporting this outcome, raise a Xero support issue quoting both ids above. + type: partial-failure-previous-connection-deletion + subtype: connection-phase-failed + title: Previous Connection Removed, New Connection Not Created + detail: The previous connection '880600c2-d302-4b9c-a88a-e0253c926ab2' on account '9f2b1c44-7a0e-4d6e-b2d1-3c8e5a7f0b11' was removed, but the new connection was not created, so the account has no feed. Resend the same item. If it keeps reporting this outcome, raise a Xero support issue quoting '880600c2-d302-4b9c-a88a-e0253c926ab2' and '9f2b1c44-7a0e-4d6e-b2d1-3c8e5a7f0b11'. + accountId: 9f2b1c44-7a0e-4d6e-b2d1-3c8e5a7f0b11 + connectionId: 880600c2-d302-4b9c-a88a-e0253c926ab2 '400': - description: 'Every item is 4xx: either the request wrote nothing at all, or the request itself + description: 'All items are 4xx: either the request wrote nothing at all, or the request itself could not be processed. - `400` guarantees all item attempts failed completely. - - Nothing survived for any item and no item reached its desired state. + A `400` guarantees that none of the items was written and none reached its desired state. - A batch in which anything partially wrote has at least one `500` item code, so it is a `207`, never a `400`. + A batch in which any item was partly written has at least one `500` item code, so it is a `207`, never a `400`. When the request itself was at fault — an unreadable body, an empty `items` @@ -251,7 +275,7 @@ paths: and there is no `items` array at all. -' + ' content: application/json: schema: @@ -282,12 +306,12 @@ paths: operationId: createFeedConnectionsForNewAccounts summary: Create Xero Bank Accounts and connect feeds to them externalDocs: - description: Partial-failure recovery by error title + description: Partial-failure recovery by error type url: https://developer.xero.com/documentation/api/bankfeeds/feedconnections-2-0-errors/#partial-failures description: 'Creates a new Xero Bank Account for each item and connects a feed to it. - `accountId` must not be supplied. An item carrying one — including an all-zeros GUID, or a + `accountId` must not be supplied. An item that includes one — including an all-zeros GUID, or a value that is not a GUID at all — is rejected, because supplying an account identifier means @@ -298,11 +322,15 @@ paths: `accountNumber` and `accountName` are required here, since they describe the account being - created. If the Organisation already holds an account with the requested name, the item is + created. If the Organisation already has an account with the requested name, the item is rejected with `account-name-already-exists` naming that account, and no account is created. -' + The same applies to a second item in the same request that uses a name an earlier item + + has just taken. + + ' parameters: - $ref: '#/components/parameters/XeroTenantId' requestBody: @@ -325,16 +353,16 @@ paths: currency: AUD responses: '200': - description: 'Every item is 2xx: each one reached its desired state and nothing is left for you to + description: 'All items are 2xx: each one reached its desired state, and there is nothing left for you - do. A created item carries `status` `SUCCESS` and `statusCode` `201`. + to do. A created item has `status` `SUCCESS` and `statusCode` `201`. A response that mixes successful items with rejected or partially failed ones is a `207`, not a `200`. -' + ' content: application/json: schema: @@ -350,12 +378,17 @@ paths: status: SUCCESS statusCode: 201 '207': - description: 'Some items did not reach their desired state. Every item has its own result, so read + description: 'Some items did not reach their desired state. Each item has its own result, so read the `items` array rather than the envelope. - `207` means the item codes were neither all 2xx nor all 4xx. A `PARTIAL_FAILURE` item carries `statusCode` `500`. On this endpoint, only `partial-failure-account-created-but-not-connected` applies (three titles). The account was created: do not resend the same NewAccount item. Find its `accountId` in `error.detail`, then follow the matching recovery row at https://developer.xero.com/documentation/api/bankfeeds/feedconnections-2-0-errors/#partial-failures . ' + Partial failures are rare, and nearly all are recoverable by your app. On this endpoint two types apply. With `partial-failure-new-account-creation` the account was created: do not resend the same NewAccount item, because its `accountName` is now taken. Connect the created `error.accountId` through ExistingAccount instead. If that request returns 409 `feed-already-connected-in-current-organisation`, the earlier attempt was recorded: treat the item as created. With `partial-failure-new-account-existence-not-confirmed` the account may or may not have been created, and nothing else was set up for it. The error has `error.accountName`, but no `error.accountId` or `error.connectionId`. Use the Accounting API to check whether an account named `error.accountName` exists. If it does, connect it through ExistingAccount. If it does not, resend the item. If your app has a user, you can show them this message instead: "Something went wrong. Please check whether your chosen account name now exists. If it does, connect it. If not, try creating the new one again." `error.subtype` is optional diagnostics. See https://developer.xero.com/documentation/api/bankfeeds/feedconnections-2-0-errors/#partial-failures . + + + `207` means the item codes were neither all 2xx nor all 4xx. A `PARTIAL_FAILURE` item has `statusCode` `500`: the item did not complete, and the state it left behind needs attention or could not be confirmed. `error.subtype` says which. A `REJECTED` item whose error is `internal-error` also has `statusCode` `500`, so it makes the response a `207` (as does a batch in which all items are like that): something unexpected went wrong for that item, and nothing was written or a write could not be confirmed, so resending the item is safe. + + ' content: application/json: schema: @@ -372,27 +405,35 @@ paths: error: type: account-name-already-exists title: Account Name Already Exists - status: 409 detail: An account named 'Sam's Credit Card' already exists in this organisation. Specify a different AccountName. + - accountToken: '10000126' + status: PARTIAL_FAILURE + statusCode: 500 + error: + type: partial-failure-new-account-existence-not-confirmed + subtype: check-accounts-or-prompt-user-retry + title: Account Creation Unconfirmed + detail: 'The account ''Everyday'' may have been created, but this could not be confirmed, and nothing else was set up for it. Check whether an account named ''Everyday'' now exists. If it does, connect it with POST FeedConnections/ExistingAccount. If it does not, resend this item.' + accountName: Everyday - accountToken: '10000125' status: PARTIAL_FAILURE statusCode: 500 error: - type: partial-failure-account-created-but-not-connected + type: partial-failure-new-account-creation + subtype: connection-phase-failed title: Account Created But Not Connected - status: 500 - detail: 'The account creation was successful, the feed connection failed. Use accountId ''e0c0e2a6-2d19-4a6e-9f0e-6f9c2a7a1b44'' with POST v2/FeedConnections/ExistingAccount to connect it. Do not retry this item unchanged: the AccountName ''Everyday'' is already taken and an identical retry will be refused.' + detail: 'Account ''e0c0e2a6-2d19-4a6e-9f0e-6f9c2a7a1b44'' was created, but no connection was set up for it. Use ''e0c0e2a6-2d19-4a6e-9f0e-6f9c2a7a1b44'' with POST FeedConnections/ExistingAccount to connect it. Do not retry this item unchanged: the AccountName ''Everyday'' is already taken and an identical retry will be refused.' + accountId: e0c0e2a6-2d19-4a6e-9f0e-6f9c2a7a1b44 + accountName: Everyday '400': - description: 'Every item is 4xx: either the request wrote nothing at all, or the request itself + description: 'All items are 4xx: either the request wrote nothing at all, or the request itself could not be processed. - `400` guarantees all item attempts failed completely. - - Nothing survived for any item and no item reached its desired state. + A `400` guarantees that none of the items was written and none reached its desired state. - A batch in which anything partially wrote has at least one `500` item code, so it is a `207`, never a `400`. + A batch in which any item was partly written has at least one `500` item code, so it is a `207`, never a `400`. When the request itself was at fault — an unreadable body, an empty `items` @@ -402,7 +443,7 @@ paths: and there is no `items` array at all. -' + ' content: application/json: schema: @@ -428,7 +469,7 @@ paths: operationId: deleteFeedConnections summary: Terminate Feed Connections externalDocs: - description: Partial-failure recovery by error title + description: Partial-failure recovery by error type url: https://developer.xero.com/documentation/api/bankfeeds/feedconnections-2-0-errors/#partial-failures description: 'Terminates the Feed Connections named in the request. Terminating a Feed Connection @@ -453,15 +494,15 @@ paths: the original response was lost, resend the same DeleteRequests item. The retry - checks whether the connection remains and terminates it if needed. The item has + checks whether the connection remains and terminates it if needed. A `SUCCESS` item on the resend - `statusCode` `204` after a successful deletion or confirmation that the connection is absent. + means the deletion is complete, including `feed-not-found-or-already-deleted` at `statusCode` `204`. If a retry keeps reporting `PARTIAL_FAILURE`, contact Xero support with the connection - id in `error.detail`. + id in `error.connectionId`. -' + ' parameters: - $ref: '#/components/parameters/XeroTenantId' requestBody: @@ -476,9 +517,9 @@ paths: - id: 880600c2-d302-4b9c-a88a-e0253c926ab2 responses: '200': - description: 'Every item is 2xx: each one reached its desired state and nothing is left for you to + description: 'All items are 2xx: each one reached its desired state, and there is nothing left for you - do. This includes a request in which every identifier named nothing to terminate, + to do. This includes a request in which none of the identifiers matched a connection to terminate, since `feed-not-found-or-already-deleted` is reported at `statusCode` `204` — the @@ -487,7 +528,7 @@ paths: A response that mixes these with rejected or partially failed items is a `207`. -' + ' content: application/json: schema: @@ -503,15 +544,19 @@ paths: error: type: feed-not-found-or-already-deleted title: Feed Connection not found or already deleted - status: 204 detail: This Feed Connection either never existed, or has already been deleted. '207': - description: 'Some items did not reach their desired state. Every item has its own result, so read + description: 'Some items did not reach their desired state. Each item has its own result, so read the `items` array rather than the envelope. - `207` means the item codes were neither all 2xx nor all 4xx. A `PARTIAL_FAILURE` item carries `statusCode` `500`. On this endpoint, only `partial-failure-delete-can-be-reattempted` applies. The Feed Connection no longer appears in GET or delivers statements, but may still appear connected in Xero. Resend the same DeleteRequests item to check whether the connection remains and terminate it if needed. The item has `statusCode` `204` after a successful retry or confirmation of absence. If it keeps reporting `PARTIAL_FAILURE`, contact Xero support with the connection id from `error.detail`. See https://developer.xero.com/documentation/api/bankfeeds/feedconnections-2-0-errors/#partial-failures . ' + Partial failures are rare, and nearly all are recoverable by your app. On this endpoint only `partial-failure-connection-deletion` applies: resend the same DeleteRequests item. It checks whether the connection remains and terminates it if needed. A `SUCCESS` item on the resend means the deletion is complete, including `feed-not-found-or-already-deleted` at `statusCode` `204`, which means the earlier attempt had already finished it. `error.subtype` is optional diagnostics. If it keeps reporting `PARTIAL_FAILURE`, contact Xero support with the connection id from `error.connectionId`. See https://developer.xero.com/documentation/api/bankfeeds/feedconnections-2-0-errors/#partial-failures . + + + `207` means the item codes were neither all 2xx nor all 4xx. A `PARTIAL_FAILURE` item has `statusCode` `500`: the item did not complete, and the state it left behind needs attention or could not be confirmed. `error.subtype` says which. A `REJECTED` item whose error is `internal-error` also has `statusCode` `500`, so it makes the response a `207`: something unexpected went wrong for that item before anything was deleted, so resending the item is safe. After a `partial-failure-connection-deletion`, the Feed Connection no longer appears in GET or delivers statements, but may still appear connected in Xero. + + ' content: application/json: schema: @@ -526,35 +571,35 @@ paths: error: type: missing-identifying-fields title: Request Is Missing Identifying Fields - status: 400 detail: The request did not include the mandatory 'Id' field. - id: 40f0469d-8197-4477-9a0d-8dd7641cf1cc status: PARTIAL_FAILURE statusCode: 500 error: - type: partial-failure-delete-can-be-reattempted + type: partial-failure-connection-deletion + subtype: connection-exists-without-feed-connection title: Feed Connection Only Partially Deleted - status: 500 - detail: 'Deletion of feed connection ''40f0469d-8197-4477-9a0d-8dd7641cf1cc'' could not be confirmed. It no longer appears in GET v2/FeedConnections or delivers statements, but may still appear connected in Xero. Resend the same DeleteRequests item: the retry confirms whether the connection remains and terminates it if needed. If the retry keeps reporting PARTIAL_FAILURE, contact Xero support quoting the connection id above.' + detail: Feed connection '40f0469d-8197-4477-9a0d-8dd7641cf1cc' was deleted and no longer appears in GET FeedConnections or receives statements, but it is still connected in Xero. Resend the same item to finish the removal. If it keeps reporting this outcome, contact Xero support quoting '40f0469d-8197-4477-9a0d-8dd7641cf1cc'. + connectionId: 40f0469d-8197-4477-9a0d-8dd7641cf1cc '400': - description: 'Every item is 4xx: either the request wrote nothing at all, or the request itself + description: 'All items are 4xx: either the request wrote nothing at all, or the request itself - could not be processed. **The guarantee a `400` carries is that nothing survived any + could not be processed. **A `400` guarantees that none of the items was written and - item and no item reached its desired state**, so a corrected request may be re-sent + none reached its desired state**, so a corrected request may be re-sent safely. An item reported as `feed-not-found-or-already-deleted` does not count towards this: - its `statusCode` is `204`, so a request made entirely of unknown identifiers is + its `statusCode` is `204`, so a request made up only of unknown identifiers is answered `200`, not `400`. Only items rejected outright — a missing or unusable `id` - — carry a 4xx code, so only they can produce a `400` envelope, and **a batch in which + — have a 4xx code, so only they can produce a `400` envelope, and **a batch in which - anything partially wrote has a `500` item code, making it a `207`**. + any item was partly deleted has a `500` item code, making it a `207`**. A request-level failure — an unreadable body, an empty `items` array, more @@ -563,7 +608,7 @@ paths: problem object with no `items` array. -' + ' content: application/json: schema: @@ -575,7 +620,6 @@ paths: error: type: missing-identifying-fields title: Request Is Missing Identifying Fields - status: 400 detail: The request did not include the mandatory 'Id' field. It must be the GUID of an existing feed connection. application/problem+json: schema: @@ -631,17 +675,17 @@ components: status: 400 detail: Missing required header Xero-Tenant-Id. Unauthorised: - description: 'The request carried no valid Xero Identity bearer token. A request missing both a token and a + description: 'The request did not include a valid Xero Identity bearer token. A request missing both a token and a required header is answered `400`, because headers are checked first. -' + ' Forbidden: description: 'The Application, the Organisation, or the user is not permitted to make this request. Read `type` to distinguish the cases. -' + ' content: application/problem+json: schema: @@ -652,11 +696,11 @@ components: status: 403 detail: The application has been suspended or terminated. UnsupportedMediaType: - description: 'The request did not carry `Content-Type: application/json`. V1 rewrote a wrong value for one + description: 'The request did not use `Content-Type: application/json`. V1 rewrote a wrong value for one legacy Application; V2 does not. -' + ' InternalError: description: An error occurred inside Xero. The request should be retried. content: @@ -682,7 +726,7 @@ components: processed. -' + ' content: application/problem+json: schema: @@ -690,11 +734,11 @@ components: schemas: Problem: type: object - description: 'An error. Served as `application/problem+json` when it describes the request as a whole, and + description: 'An error. Served as `application/problem+json` when it describes the request as a whole. - carried inside the `error` property of an item result when it describes one item. + The `error` of an item result is an `ItemError`, which has the same fields except `status`. -' + ' properties: type: type: string @@ -715,26 +759,199 @@ components: - account-name-already-exists - bank-feed-not-found - feed-not-found-or-already-deleted - - partial-failure-account-created-but-not-connected - - partial-failure-migration-can-be-reattempted - - partial-failure-delete-can-be-reattempted - - partial-failure-connection-created-but-not-recorded + - partial-failure-new-account-creation + - partial-failure-previous-connection-deletion + - partial-failure-connection-creation + - partial-failure-connection-deletion + - partial-failure-new-account-existence-not-confirmed - too-many-requests - internal-error + subtype: + type: string + description: 'Present only on a partial failure (a `partial-failure-*` `type`). Names the exact cause + + within the `type`. Reading it is optional: the `type` alone fixes the recovery action and + + which identifier fields are present, so branch on `type` and use `subtype` for diagnostics. + + ' + enum: + - connection-phase-failed + - deletion-phase-failed + - deletion-phase-not-confirmed + - connection-existence-not-confirmed + - connection-exists-without-feed-connection + - feed-connection-existence-not-confirmed-can-check-or-retry + - check-accounts-or-prompt-user-retry title: type: string description: A short human-readable summary of the error. status: type: integer format: int32 - description: 'The HTTP status this error corresponds to. Inside an item result this is the status of + description: 'The HTTP status this error corresponds to. It is the status of the response. An item + + result does not repeat it in its `error`: read the item''s `statusCode` instead. + + ' + detail: + type: string + description: A human-readable explanation specific to this occurrence. + accountId: + type: string + format: uuid + description: 'Present only on a partial failure. The Xero Bank Account the item concerns. On + + `partial-failure-new-account-creation`, the account that was created: connect it through + + `POST /FeedConnections/ExistingAccount`. On `partial-failure-previous-connection-deletion` + + and `partial-failure-connection-creation`, the account being connected. Absent on + + `partial-failure-connection-deletion` and + + `partial-failure-new-account-existence-not-confirmed`, where the account may not exist. + + ' + accountName: + type: string + description: 'Present only on a partial failure of type `partial-failure-new-account-creation` or + + `partial-failure-new-account-existence-not-confirmed`. The name of the account that was + + created, which is now taken; on `partial-failure-new-account-existence-not-confirmed`, the + + name of the account that may have been created. + + ' + connectionId: + type: string + format: uuid + description: 'Present only on a partial failure. On `partial-failure-previous-connection-deletion`, the + + previous connection on the account (removed, or being removed). On + + `partial-failure-connection-creation`, the connection this request created or was + + creating: the id it was given before the create (the Feed Connection `id` if it was + + recorded). When the subtype is `connection-existence-not-confirmed`, the create''s outcome + + is unknown and the connection may not exist in Xero. On + + `partial-failure-connection-deletion`, the connection being deleted (the item `id` also + + echoes it). Absent on `partial-failure-new-account-creation` and + + `partial-failure-new-account-existence-not-confirmed`. + + ' + ItemError: + type: object + description: 'The `error` of an item result. It has the same fields as `Problem`, except `status`: the + + item''s own `statusCode` is its HTTP status, so it is not repeated here. + + ' + properties: + type: + type: string + description: Identifies the error. + enum: + - invalid-request + - invalid-application + - suspended-or-terminated-application + - invalid-organisation-bank-feeds + - invalid-organisation-multi-currency + - invalid-feed-connection-for-organisation + - invalid-user-role + - invalid-account-token + - missing-identifying-fields + - invalid-country-specified + - account-not-valid + - feed-already-connected-in-current-organisation + - account-name-already-exists + - bank-feed-not-found + - feed-not-found-or-already-deleted + - partial-failure-new-account-creation + - partial-failure-previous-connection-deletion + - partial-failure-connection-creation + - partial-failure-connection-deletion + - partial-failure-new-account-existence-not-confirmed + - too-many-requests + - internal-error + subtype: + type: string + description: 'Present only on a partial failure (a `partial-failure-*` `type`). Names the exact cause + + within the `type`. Reading it is optional: the `type` alone fixes the recovery action and - that item, which need not be the status of the response as a whole. + which identifier fields are present, so branch on `type` and use `subtype` for diagnostics. -' + ' + enum: + - connection-phase-failed + - deletion-phase-failed + - deletion-phase-not-confirmed + - connection-existence-not-confirmed + - connection-exists-without-feed-connection + - feed-connection-existence-not-confirmed-can-check-or-retry + - check-accounts-or-prompt-user-retry + title: + type: string + description: A short human-readable summary of the error. detail: type: string description: A human-readable explanation specific to this occurrence. + accountId: + type: string + format: uuid + description: 'Present only on a partial failure. The Xero Bank Account the item concerns. On + + `partial-failure-new-account-creation`, the account that was created: connect it through + + `POST /FeedConnections/ExistingAccount`. On `partial-failure-previous-connection-deletion` + + and `partial-failure-connection-creation`, the account being connected. Absent on + + `partial-failure-connection-deletion` and + + `partial-failure-new-account-existence-not-confirmed`, where the account may not exist. + + ' + accountName: + type: string + description: 'Present only on a partial failure of type `partial-failure-new-account-creation` or + + `partial-failure-new-account-existence-not-confirmed`. The name of the account that was + + created, which is now taken; on `partial-failure-new-account-existence-not-confirmed`, the + + name of the account that may have been created. + + ' + connectionId: + type: string + format: uuid + description: 'Present only on a partial failure. On `partial-failure-previous-connection-deletion`, the + + previous connection on the account (removed, or being removed). On + + `partial-failure-connection-creation`, the connection this request created or was + + creating: the id it was given before the create (the Feed Connection `id` if it was + + recorded). When the subtype is `connection-existence-not-confirmed`, the create''s outcome + + is unknown and the connection may not exist in Xero. On + + `partial-failure-connection-deletion`, the connection being deleted (the item `id` also + + echoes it). Absent on `partial-failure-new-account-creation` and + + `partial-failure-new-account-existence-not-confirmed`. + + ' Pagination: type: object properties: @@ -757,18 +974,18 @@ components: which is not returned. -' + ' AccountType: type: string description: 'The high-level type of the account. `BANK` covers every account type other than a credit card. -' + ' enum: - BANK - CREDITCARD FeedConnection: type: object - description: A Feed Connection as Xero holds it. + description: A Feed Connection as Xero records it. properties: id: type: string @@ -832,7 +1049,7 @@ components: though the field were absent. -' + ' accountToken: type: string maxLength: 50 @@ -840,7 +1057,7 @@ components: financial institute. Some financial institutes additionally constrain its format. -' + ' accountType: $ref: '#/components/schemas/AccountType' currency: @@ -849,9 +1066,9 @@ components: maxLength: 3 description: 'ISO-4217 currency code. Must match the currency of the Xero Bank Account named by - `accountId`, and must be a currency the Organisation holds. + `accountId`, and must be a currency the Organisation has. -' + ' country: type: string minLength: 2 @@ -860,7 +1077,7 @@ components: regions. Talk to your Partner Manager to confirm whether this applies to you. -' + ' accountNumber: type: string description: Ignored. Taken from the Xero Bank Account named by `accountId`. @@ -895,7 +1112,7 @@ components: financial institute. -' + ' accountType: $ref: '#/components/schemas/AccountType' accountNumber: @@ -907,20 +1124,20 @@ components: digits, and digits only. -' + ' accountName: type: string maxLength: 30 description: 'The name for the Xero Bank Account being created. Rejected if the Organisation already - holds an account with this name. + has an account with this name. -' + ' currency: type: string minLength: 3 maxLength: 3 - description: ISO-4217 currency code. Must be a currency the Organisation holds. + description: ISO-4217 currency code. Must be a currency the Organisation has. country: type: string minLength: 2 @@ -929,7 +1146,7 @@ components: regions. -' + ' DeleteFeedConnectionsRequest: type: object required: @@ -943,7 +1160,7 @@ components: may appear twice. -' + ' items: $ref: '#/components/schemas/FeedConnectionToDelete' FeedConnectionToDelete: @@ -960,7 +1177,7 @@ components: are not supported. -' + ' BulkFeedConnectionResponse: type: object description: One result per request item, in request order. @@ -977,9 +1194,9 @@ components: Read `status` rather than inferring the outcome from the presence of `error`. On a - termination an item can carry both `SUCCESS` and an `error`, when the identifier named + termination an item can have both `SUCCESS` and an `error`, when the identifier did not - nothing to terminate. + match a connection to terminate. Read `statusCode` per item as well, rather than deriving it from the envelope: it is the @@ -988,9 +1205,9 @@ components: no-op, not a failure; one of `500` on a `partial-failure-*` type is not a server fault to - retry blindly. + retry blindly. The item''s `error` does not repeat the number as `status`. -' + ' properties: id: type: string @@ -1002,40 +1219,42 @@ components: On a termination, the identifier supplied in the request, echoed back; absent only when - the item carried no usable identifier. + the item did not include a usable identifier. -' + ' accountToken: type: string description: 'The `accountToken` supplied in the request, echoed back, including on a rejected item. Not returned on a termination. -' + ' status: type: string description: '`SUCCESS` means the item reached the state the request asked for — on a create the connection exists, on a termination it is gone, including the idempotent case where it - was already gone. `REJECTED` means it was refused and nothing was written, and `error` + was already gone. `REJECTED` means nothing was written, or a write could not be - says why. `PARTIAL_FAILURE` means the item did not complete **and** something was + confirmed, so a resend is safe, and `error` says why. - written that survives; `error.detail` names what, and the item needs attention that + `PARTIAL_FAILURE` means the item did not complete, and the state it left behind needs - neither of the other two values implies. + attention or could not be confirmed. `error.subtype` says which, `error.detail` + + describes it, and the item needs attention that neither of the other two values + + implies. A client deserialising this into a closed set of `SUCCESS` and `REJECTED` will fail on `PARTIAL_FAILURE`. That is intended rather than an oversight: binding it silently to - either of the other two would hide surviving state from the partner who has to act on - - it. + either of the other two would hide state that the partner has to act on. -' + ' enum: - SUCCESS - REJECTED @@ -1043,20 +1262,20 @@ components: statusCode: type: integer format: int32 - description: 'The numeric status this item carries in its own right: `201` on a created connection, + description: 'The numeric status of this item: `201` on a created connection, `204` on a terminated or already-absent one, a 4xx on a rejection, `500` on a partial - failure. The response envelope is computed from every item''s own `statusCode` — every + failure or on a rejection whose error is `internal-error`. The response envelope is computed from the items'' `statusCode` values: all 2xx is `200`, - item 2xx is `200`, every item 4xx is `400`, anything else is `207` — so a partner can + all 4xx is `400`, anything else is `207`. So a partner can - size up one item without interpreting `status` and `error` together. Never `202` and + size up one item without reading `status` and `error` together. Never `202` and never `207`: those are envelope-only, and an item-level `207` would be numerically - inside 2xx, letting an all-partial-failure batch compute to a reassuring `200`. + inside 2xx, so a batch of partial failures could be reported as `200`. -' + ' error: - $ref: '#/components/schemas/Problem' + $ref: '#/components/schemas/ItemError'