# Regulated Third Party Providers (TPP)

**Guide Group:** Regulated Third Party Providers (TPP)

---

## Introduction

Register with eBay

Finances API

Fulfillment API

Post-Order API

Trading API

#### Register with eBay

Payment services regulations applicable in the EU and the UK require all regulated Account Servicing Payment Service Providers (ASPSPs) to provide secure APIs that allow regulated Third Party Payment Providers (TPPs) to access account and payment services on behalf of account holders. The regulations further dictate that a TPP should be able to use a qualified certificate issued by any Electronic Identification, Authentication and Trust Services (eIDAS) Qualified Trust Service Provider (QTSP) or issued by the OpenBanking Directory in order to identify and authenticate themselves to an ASPSP.

This document provides information about how TPPs can register with eBay and obtain all necessary client details and tokens required to make API calls for clients domiciled in the EU or the UK.

**Note:** Each TPP may register up to 15 different applications provided each application has a unique software ID.

##### Production/Sandbox environments

In addition to its standard Production environment, eBay provides developers access to a Sandbox environment in which developers can test the behavior of their applications throughout development.

##### Registration process

This process applies to registering clients for both eBay's Production environment as well as eBay's Sandbox (test) environment.

**Note:** There are some minor differences in the procedure that are unique to the Sandbox environment. These will be identified and described where applicable.

###### Step 1: Register your client with eBay

TPPs in possession of a valid eIDAS Qualified Website Authentication Certificate (QWAC) or OpenBanking Website Authentication Certificate (OBWAC) may register their client with eBay using the [Client Registration API](/api-docs/developer/client-registration/overview.html) which is based on, and conforms with, [RFC 7591 - OAuth 2.0 Dynamic Client Registration Protocol](https://datatracker.ietf.org/doc/html/rfc7591) (except as noted in the [List of Deviations from RFC 7591](/api-docs/developer/client-registration/overview.html#deviations)). Requests that conform with **RFC 7591** will be accepted, however some fields will be ignored.

**Note:** eBay does not support Qualified Electronic Seal (QSEAL) certificates.

**Important!** When calling the **registerClient** method, Third-Party Providers (TPPs) are required to pass their valid eIDAS or OpenBanking Directory certificate to eBay via Mutual Transport Layer Security (MTLS) handshake _Certificate Request_ messages.

Refer to the [Client Registration API reference documentation](/api-docs/developer/client-registration/overview.html) for complete information about using the API.

**Note:** Make note of the following values as they will be required in upcoming steps:

*   `client_id` value
*   `client_secret` value

_Using Sandbox for testing_

As mentioned above, developers who wish to test their applications may do so using eBay's Sandbox environment. However, in order to do so, the application must first be registered with eBay's Sandbox environment by calling the **Register Client API** using the following Sandbox Resource URI:

POST https://tppzsb.ebay.com/developer/registration/v1/client/register

Once the application has been successfully registered, login credentials for a Test User (i.e., _username_ and _password_,) may then be ascertained. This is a fairly straightforward process that uses a portion of the `client_ID` returned by the API.

The prototype for both _username_ and _password_ is:

TESTUSER\_{characters\_following\_**SBX-**\_in\_clientID}

For example, a registered application returns:

"clientId": "SMP01-clientid-SBX-abcde0123-4f56g789"

The corresponding Sandbox credentials would be:

**username:** TESTUSER\_abcde0123-4f56g789

**password:** TESTUSER\_abcde0123-4f56g789

###### Step 2: Obtain user consent

A TPP application must obtain the user's consent before it can make requests for that user.

Refer to [Getting User Consent](/api-docs/static/oauth-consent-request.html) for complete information.

**Note:** Verify that the appropriate target endpoint is being used based on the environment for which the application is being registered.

**Sandbox Environment:** When obtaining consent within the Sandbox environment, when prompted, use the [Sandbox credentials](#creds) created in [Step 1](#step1) above to login.

Once the user has granted their consent, the user is redirected per the first `redirect_uri` in the `redirect_uris` array returned by the Register Client API call. The single-use _authorization code_ is returned as the `code` query parameter for the redirect\_uri.

For example, the following `redirect_uri` is returned:

https://client.example.org/callback2?code=v\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*D&expires\_in=299

The _authorization code_ is:

`v********************D`

The _authorization code_ is required when creating a user access token in [Step 3](#step3).

**Note:** This _authorization code_ cannot be used to make API requests. A valid User Access Token is required.

###### Step 3: Create user access token

Finally, in order to make API calls, a _User Access Token_ must be created/retrieved by issuing an _Authorization Code Grant Request_. The following previously generated and returned values are required as part of this request:

*   `[client_id](/api-docs/developer/client-registration/resources/register/methods/registerClient#response.client_id)` (returned by the Client Registration API)
*   `[client_secret](/api-docs/developer/client-registration/resources/register/methods/registerClient#response.client_secret)` (returned by the Client Registration API)
*   _authorization code_ (returned by User Consent in [Step 2](#step2))

Refer to [Exchanging the authorization code for a User access token](/api-docs/static/oauth-auth-code-grant-request.html) for complete information.

**Note:** Verify that the appropriate target endpoint is being used based on the environment for which the application is being registered.

###### Step 4: Make API calls

Refer to the following tabs for complete information about making API calls within the Production and Sandbox environments:

*   [Finances API](#)
*   [Fulfillment API](#)
*   [Post-Order API](#)
*   [Trading API](#)

##### Error codes

When issuing [Finances](#), [Fulfillment](#), [Post-Order](#), and/or [Trading](#) API calls in either the Production or Sandbox environment, an error code may be returned if information is missing or improperly formatted, a certificate has expired, etc. Refer to the following table for information about these error codes.

Code

Meaning

215500

Caller is not registered

215501

Invalid license

215502

Certificate not issued by a valid Qtsp

215503

Certificate expired

215504

Certificate revoked

215506

Not a valid signature

215507

Role not matching

215508

Invalid certificate

215510

Missing certificate

215511

Internal errors as validating client certificate

215512

Internal errors as calling another service

#### Finances API

This page provides information required to call each method of the Finances API available for use by registered TPPs.

**Note:** When making the following call(s), it is imperative that the appropriate **Resource URI** listed for each method be used. Using a Gateway URI other than that listed below will result in failed calls.

The Finances API is used to retrieve detailed information on seller payouts for eBay orders, and also retrieve details on all monetary transactions on eBay's system between the seller, buyer, and eBay.

##### getPayout

This method retrieves details for a specific seller payout. The unique identfier of the payout is passed in as a path parameter at the end of the call URI.

Use the [getPayouts](#payouts) method to retrieve unique identifiers of payouts.

*   **Resource URI (Production):** `GET https://tppz.ebay.com/sell/finances/v1/payout/{payout_Id}`
*   **Resource URI (Sandbox):** `GET https://tppz.sandbox.ebay.com/sell/finances/v1/payout/{payout_Id}`
*   Refer to the [getPayout Reference Documentation](/api-docs/sell/finances/resources/payout/methods/getPayout) for additional information, including:
    *   URI parameters
    *   Request payload and fields
    *   Response payload and fields
    *   Status and error codes, and warnings

##### getPayouts

This method is used to retrieve the details of one or more seller payouts.

*   **Resource URI (Production):** `GET https://tppz.ebay.com/sell/finances/v1/payout?limit=integer&offset=integer&filter=FilterField&sort=SortField`
*   **Resource URI (Sandbox):** `GET https://tppz.sandbox.ebay.com/sell/finances/v1/payout?limit=integer&offset=integer&filter=FilterField&sort=SortField`
*   Refer to the [getPayouts Reference Documentation](/api-docs/sell/finances/resources/payout/methods/getPayouts) for additional information, including:
    *   URI parameters
    *   Request payload and fields
    *   Response payload and fields
    *   Status and error codes, and warnings

##### getPayoutSummary

This method is used to retrieve cumulative values for payouts in a particular state, or all states.

*   **Resource URI (Production):** `GET https://tppz.ebay.com/sell/finances/v1/payout_summary?filter=FilterField`
*   **Resource URI (Sandbox):** `GET https://tppz.sandbox.ebay.com/sell/finances/v1/payout_summary?filter=FilterField`
*   Refer to the [getPayoutSummary Reference Documentation](/api-docs/sell/finances/resources/payout/methods/getPayoutSummary) for additional information, including:
    *   URI parameters
    *   Request payload and fields
    *   Response payload and fields
    *   Status and error codes, and warnings

##### getSellerFundsSummary

This method retrieves all pending funds that have not yet been distributed through a seller payout.

*   **Resource URI (Production):** `GET https://tppz.ebay.com/sell/finances/v1/seller_funds_summary`
*   **Resource URI (Sandbox):** `GET https://tppz.sandbox.ebay.com/sell/finances/v1/seller_funds_summary`
*   Refer to the [getSellerFundsSummary Reference Documentation](/api-docs/sell/finances/resources/seller_funds_summary/methods/getSellerFundsSummary) for additional information, including:
    *   URI parameters
    *   Request payload and fields
    *   Response payload and fields
    *   Status and error codes, and warnings

##### getTransactions

This method allows a seller to retrieve monetary transactions.

*   **Resource URI (Production):** `GET https://tppz.ebay.com/sell/finances/v1/transaction?limit=integer&offset=integer&filter=FilterField&sort=SortField`
*   **Resource URI (Sandbox):** `GET https://tppz.sandbox.ebay.com/sell/finances/v1/transaction?limit=integer&offset=integer&filter=FilterField&sort=SortField`
*   Refer to the [getTransactions Reference Documentation](/api-docs/sell/finances/resources/transaction/methods/getTransactions) for additional information, including:
    *   URI parameters
    *   Request payload and fields
    *   Response payload and fields
    *   Status and error codes, and warnings

##### getTransactionSummary

This method retrieves cumulative values for five types of monetary transactions: order sales, seller credits, buyer refunds, buyer-initiated payment disputes, shipping label purchases, and transfers.

*   **Resource URI (Production):** `GET https://tppz.ebay.com/sell/finances/v1/transaction_summary?filter=FilterField`
*   **Resource URI (Sandbox):** `GET https://tppz.sandbox.ebay.com/sell/finances/v1/transaction_summary?filter=FilterField`
*   Refer to the [getTransactionSummary Reference Documentation](/api-docs/sell/finances/resources/transaction/methods/getTransactionSummary) for additional information, including:
    *   URI parameters
    *   Request payload and fields
    *   Response payload and fields
    *   Status and error codes, and warnings

##### getTransfer

This method retrieves detailed information regarding a `TRANSFER` transaction type.

*   **Resource URI (Production):** `GET https://tppz.ebay.com/sell/finances/v1/transfer/{transfer_Id}`
*   **Resource URI (Sandbox):** `GET https://tppz.sandbox.ebay.com/sell/finances/v1/transfer/{transfer_Id}`
*   Refer to the [getTransfer Reference Documentation](/api-docs/sell/finances/resources/transfer/methods/getTransfer) for additional information, including:
    *   URI parameters
    *   Request payload and fields
    *   Response payload and fields
    *   Status and error codes, and warnings

##### API Changes

For all the API changes, please refer to the [Finances API Release Notes](/api-docs/sell/finances/release-notes.html) page. For all incompatible changes and API deprecations and decommissions, please refer to the [API Deprecation Status](/develop/get-started/api-deprecation-status) page.

#### Fulfillment API

This page provides information required to call each method of the Fulfillment API available for use by registered TPPs.

**Note:** When making the following call(s), it is imperative that the appropriate **Resource URI** listed for each method be used. Using a Gateway URI other than that listed below will result in failed calls.

The Fulfillment API is used to retrieve and fulfill orders, issue refunds, and manage third-party payment disputes initiated by buyers.

##### issueRefund

This method allows a seller to issue a full or partial refund to a buyer for an order.

*   **Resource URI (Production):** `POST https://tpp.ebay.com/sell/fulfillment/v1/order/{order_id}/issue_refund`
*   **Resource URI (Sandbox):** `POST https://tpp.sandbox.ebay.com/sell/fulfillment/v1/order/{order_id}/issue_refund`
*   Refer to the [issueRefund Reference Documentation](/api-docs/sell/fulfillment/resources/order/methods/issueRefund) for additional information, including:
    *   URI parameters
    *   Request payload and fields
    *   Response payload and fields
    *   Status and error codes, and warnings

##### API Changes

For all the API changes, please refer to the [Fulfillment API Release Notes](/api-docs/sell/fulfillment/static/release-notes.html) page. For all incompatible changes and API deprecations and decommissions, please refer to the [API Deprecation Status](/develop/get-started/api-deprecation-status) page.

#### Post-Order API

This page provides information required to call each method of the Post-Order API available for use by registered TPPs.

**Note:** When making the following call(s), it is imperative that the appropriate **Resource URI** listed for each method be used. Using a Gateway URI other than that listed below will result in failed calls.

The Post-Order API allows a buyer to cancel, return, and inquire about orders.

##### Issue Inquiry Refund

This method allows a seller to issue a full refund to a buyer for a missing line item. This method will be used if the buyer is seeking a full refund for the missing line item and the seller has yet to ship the line item.

*   **Resource URI (Production):** `POST https://tpp.ebay.com/post-order/v2/inquiry/{inquiryId}/issue_refund`
*   Refer to the [Issue Inquiry Refund Reference Documentation](/Devzone/post-order/post-order_v2_inquiry-inquiryid_issue_refund__post.html) for additional information, including:
    *   URI parameters
    *   Request payload and fields
    *   Response payload and fields
    *   Status and error codes, and warnings

##### Issue Case Refund

This method issues a full refund to a buyer to resolve an Item Not Received (INR) or Return case that was filed against the seller.

*   **Resource URI (Production):** `POST https://tpp.ebay.com/post-order/v2/casemanagement/{caseId}/issue_refund`
*   Refer to the [Issue Case Refund Reference Documentation](/Devzone/post-order/post-order_v2_casemanagement-caseid_issue_refund__post.html) for additional information, including:
    *   URI parameters
    *   Request payload and fields
    *   Response payload and fields
    *   Status and error codes, and warnings

##### Issue Return Refund

This method issues a refund to the buyer.

*   **Resource URI (Production):** `POST https://tpp.ebay.com/post-order/v2/return/{returnId}/issue_refund`
*   Refer to the [Issue Return Refund Reference Documentation](/Devzone/post-order/post-order_v2_return-returnid_issue_refund__post.html) for additional information, including:
    *   URI parameters
    *   Request payload and fields
    *   Response payload and fields
    *   Status and error codes, and warnings

##### Process Return Request

This method is used by either a seller or buyer to perform an action against a return request.

*   **Resource URI (Production):** `POST https://tpp.ebay.com/post-order/v2/return/{returnId}/decide`
*   Refer to the [Process Return Request Reference Documentation](/Devzone/post-order/post-order_v2_return-returnid_decide__post.html) for additional information, including:
    *   URI parameters
    *   Request payload and fields
    *   Response payload and fields
    *   Status and error codes, and warnings

##### Create Cancellation Request

This method initiates an order cancellation on behalf of a seller and, if needed, can create an order cancellation on behalf of a buyer.

*   **Resource URI (Production):** `POST https://tpp.ebay.com/post-order/v2/cancellation`
*   Refer to the [Create Cancellation Request Reference Documentation](/devzone/post-order/post-order_v2_cancellation__post.html) for additional information, including:
    *   URI parameters
    *   Request payload and fields
    *   Response payload and fields
    *   Status and error codes, and warnings

##### Approve Cancellation Request

This method approves a buyer's order cancellation request on behalf of the seller.

*   **Resource URI (Production):** `POST https://tpp.ebay.com/post-order/v2/cancellation/{cancelId}/approve`
*   Refer to the [Approve Cancellation Request Reference Documentation](/devzone/post-order/post-order_v2_cancellation-cancelid_approve__post.html) for additional information, including:
    *   URI parameters
    *   Request payload and fields
    *   Response payload and fields
    *   Status and error codes, and warnings

##### API Changes

For all the API changes, please refer to the [Post-Order API Release Notes](/Devzone/post-order/releasenotes.html) page. For all incompatible changes and API deprecations and decommissions, please refer to the [API Deprecation Status](/develop/get-started/api-deprecation-status) page.

#### Trading API

**Tip:** Although the GetAccount call of the Trading API is still supported, we strongly recommend that new developers and TPPs consider using the getTransactions method of the Finances API as an alternative. The getTransactions method has more robust search filters than GetAccount, and returns more detailed information about money that is exchanged between buyer, seller, and eBay.

This page provides information required to call each method of the Trading API available for use by registered TPPs.

**Note:** When making the following call(s), it is imperative that the appropriate **URI** listed for each method be used. Using a URI other than that listed below will result in failed calls.

The Trading API allows sellers to list and manage inventory, fulfill orders, and communicate with customers.

##### GetAccount

This method retrieves a seller's invoice data for their eBay account, including the account's summary data.

This method is available in two formats:

*   SOAP format
*   XML format

Information and required values are provided below in order to call `GetAccount` using either of these formats.

*   **SOAP API URIs**
    *   **Production:** `https://tpp.ebay.com/wsapi`
    *   **Sandbox:** `https://tpp.sandbox.ebay.com/wsapi`
*   **XML API URIs**
    *   **Production:** `https://tpp.ebay.com/ws/api.dll`
    *   **Sandbox:** `https://tpp.sandbox.ebay.com/ws/api.dll`
*   **HTTP Headers:**
    *   **Required:** `X-EBAY-API-CALL-NAME:GetAccount`
    *   **Required:** `X-EBAY-API-IAF-TOKEN:{User Access Token}`
    *   **Recommended:** `X-EBAY-API-SITEID:{numeric site id}`
        
        This is the numeric ID for the specific eBay site to which you want to send the request. Refer to [SiteCodeType](/devzone/XML/docs/Reference/eBay/types/SiteCodeType.html) for the list of valid site ID values.
        
        Note that **numeric values** must be used. For example, for Australia, the Site ID value is **15**.
        
*   Refer to the [GetAccount Reference Documentation](/Devzone/XML/docs/Reference/eBay/GetAccount.html) for additional information, including:
    *   URI parameters
    *   Request payload and fields
    *   Response payload and fields
    *   Status and error codes, and warnings

##### API Changes

For all the API changes, please refer to the [Trading API Release Notes](/devzone/xml/docs/releasenotes.html) page. For all incompatible changes and API deprecations and decommissions, please refer to the [API Deprecation Status](/develop/get-started/api-deprecation-status) page.

function switchToTab(tabName) { $('#' + tabName).click(); }; /\* Highlight.js 10.7.1 (421b23b0) License: BSD-3-Clause Copyright (c) 2006-2021, Ivan Sagalaev \*/ var hljs = function () { "use strict"; function e(t) { return t instanceof Map ? t.clear = t.delete = t.set = () => { throw Error("map is read-only") } : t instanceof Set && (t.add = t.clear = t.delete = () => { throw Error("set is read-only") }), Object.freeze(t), Object.getOwnPropertyNames(t).forEach((n => { var i = t\[n\] ; "object" != typeof i || Object.isFrozen(i) || e(i) })), t } var t = e, n = e; t.default = n ; class i { constructor(e) { void 0 === e.data && (e.data = {}), this.data = e.data, this.isMatchIgnored = !1 } ignoreMatch() { this.isMatchIgnored = !0 } } function s(e) { return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#x27;") } function a(e, ...t) { const n = Object.create(null); for (const t in e) n\[t\] = e\[t\] ; return t.forEach((e => { for (const t in e) n\[t\] = e\[t\] })), n } const r = e => !!e.kind ; class l { constructor(e, t) { this.buffer = "", this.classPrefix = t.classPrefix, e.walk(this) } addText(e) { this.buffer += s(e) } openNode(e) { if (!r(e)) return; let t = e.kind ; e.sublanguage || (t = \`${this.classPrefix}${t}\`), this.span(t) } closeNode(e) { r(e) && (this.buffer += "</span>") } value() { return this.buffer } span(e) { this.buffer += \`<span class="${e}">\` } } class o { constructor() { this.rootNode = { children: \[\] }, this.stack = \[this.rootNode\] } get top() { return this.stack\[this.stack.length - 1\] } get root() { return this.rootNode } add(e) { this.top.children.push(e) } openNode(e) { const t = { kind: e, children: \[\] } ; this.add(t), this.stack.push(t) } closeNode() { if (this.stack.length > 1) return this.stack.pop() } closeAllNodes() { for (; this.closeNode();); } toJSON() { return JSON.stringify(this.rootNode, null, 4) } walk(e) { return this.constructor.\_walk(e, this.rootNode) } static \_walk(e, t) { return "string" == typeof t ? e.addText(t) : t.children && (e.openNode(t), t.children.forEach((t => this.\_walk(e, t))), e.closeNode(t)), e } static \_collapse(e) { "string" != typeof e && e.children && (e.children.every((e => "string" == typeof e)) ? e.children = \[e.children.join("")\] : e.children.forEach((e => { o.\_collapse(e) }))) } } class c extends o { constructor(e) { super(), this.options = e } addKeyword(e, t) { "" !== e && (this.openNode(t), this.addText(e), this.closeNode()) } addText(e) { "" !== e && this.add(e) } addSublanguage(e, t) { const n = e.root ; n.kind = t, n.sublanguage = !0, this.add(n) } toHTML() { return new l(this, this.options).value() } finalize() { return !0 } } function g(e) { return e ? "string" == typeof e ? e : e.source : null } const u = /\\\[(?:\[^\\\\\\\]\]|\\\\.)\*\\\]|\\(\\??|\\\\(\[1-9\]\[0-9\]\*)|\\\\./, h = "\[a-zA-Z\]\\\\w\*", d = "\[a-zA-Z\_\]\\\\w\*", f = "\\\\b\\\\d+(\\\\.\\\\d+)?", p = "(-?)(\\\\b0\[xX\]\[a-fA-F0-9\]+|(\\\\b\\\\d+(\\\\.\\\\d\*)?|\\\\.\\\\d+)(\[eE\]\[-+\]?\\\\d+)?)", m = "\\\\b(0b\[01\]+)", b = { begin: "\\\\\\\\\[\\\\s\\\\S\]", relevance: 0 }, E = { className: "string", begin: "'", end: "'", illegal: "\\\\n", contains: \[b\] }, x = { className: "string", begin: '"', end: '"', illegal: "\\\\n", contains: \[b\] }, v = { begin: /\\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\\b/ }, w = (e, t, n = {}) => { const i = a({ className: "comment", begin: e, end: t, contains: \[\] }, n) ; return i.contains.push(v), i.contains.push({ className: "doctag", begin: "(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):", relevance: 0 }), i }, y = w("//", "$"), N = w("/\\\\\*", "\\\\\*/"), R = w("#", "$"); var \_ = Object.freeze({ \_\_proto\_\_: null, MATCH\_NOTHING\_RE: /\\b\\B/, IDENT\_RE: h, UNDERSCORE\_IDENT\_RE: d, NUMBER\_RE: f, C\_NUMBER\_RE: p, BINARY\_NUMBER\_RE: m, RE\_STARTERS\_RE: "!|!=|!==|%|%=|&|&&|&=|\\\\\*|\\\\\*=|\\\\+|\\\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\\\?|\\\\\[|\\\\{|\\\\(|\\\\^|\\\\^=|\\\\||\\\\|=|\\\\|\\\\||~", SHEBANG: (e = {}) => { const t = /^#!\[ \]\*\\// ; return e.binary && (e.begin = ((...e) => e.map((e => g(e))).join(""))(t, /.\*\\b/, e.binary, /\\b.\*/)), a({ className: "meta", begin: t, end: /$/, relevance: 0, "on:begin": (e, t) => { 0 !== e.index && t.ignoreMatch() } }, e) }, BACKSLASH\_ESCAPE: b, APOS\_STRING\_MODE: E, QUOTE\_STRING\_MODE: x, PHRASAL\_WORDS\_MODE: v, COMMENT: w, C\_LINE\_COMMENT\_MODE: y, C\_BLOCK\_COMMENT\_MODE: N, HASH\_COMMENT\_MODE: R, NUMBER\_MODE: { className: "number", begin: f, relevance: 0 }, C\_NUMBER\_MODE: { className: "number", begin: p, relevance: 0 }, BINARY\_NUMBER\_MODE: { className: "number", begin: m, relevance: 0 }, CSS\_NUMBER\_MODE: { className: "number", begin: f + "(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?", relevance: 0 }, REGEXP\_MODE: { begin: /(?=\\/\[^/\\n\]\*\\/)/, contains: \[{ className: "regexp", begin: /\\//, end: /\\/\[gimuy\]\*/, illegal: /\\n/, contains: \[b, { begin: /\\\[/, end: /\\\]/, relevance: 0, contains: \[b\] }\] }\] }, TITLE\_MODE: { className: "title", begin: h, relevance: 0 }, UNDERSCORE\_TITLE\_MODE: { className: "title", begin: d, relevance: 0 }, METHOD\_GUARD: { begin: "\\\\.\\\\s\*\[a-zA-Z\_\]\\\\w\*", relevance: 0 }, END\_SAME\_AS\_BEGIN: e => Object.assign(e, { "on:begin": (e, t) => { t.data.\_beginMatch = e\[1\] }, "on:end": (e, t) => { t.data.\_beginMatch !== e\[1\] && t.ignoreMatch() } }) }); function k(e, t) { "." === e.input\[e.index - 1\] && t.ignoreMatch() } function M(e, t) { t && e.beginKeywords && (e.begin = "\\\\b(" + e.beginKeywords.split(" ").join("|") + ")(?!\\\\.)(?=\\\\b|\\\\s)", e.\_\_beforeBegin = k, e.keywords = e.keywords || e.beginKeywords, delete e.beginKeywords, void 0 === e.relevance && (e.relevance = 0)) } function O(e, t) { Array.isArray(e.illegal) && (e.illegal = ((...e) => "(" + e.map((e => g(e))).join("|") + ")")(...e.illegal)) } function A(e, t) { if (e.match) { if (e.begin || e.end) throw Error("begin & end are not supported with match") ; e.begin = e.match, delete e.match } } function L(e, t) { void 0 === e.relevance && (e.relevance = 1) } const I = \["of", "and", "for", "in", "not", "or", "if", "then", "parent", "list", "value"\] ; function j(e, t, n = "keyword") { const i = {} ; return "string" == typeof e ? s(n, e.split(" ")) : Array.isArray(e) ? s(n, e) : Object.keys(e).forEach((n => { Object.assign(i, j(e\[n\], t, n)) })), i; function s(e, n) { t && (n = n.map((e => e.toLowerCase()))), n.forEach((t => { const n = t.split("|") ; i\[n\[0\]\] = \[e, B(n\[0\], n\[1\])\] })) } } function B(e, t) { return t ? Number(t) : (e => I.includes(e.toLowerCase()))(e) ? 0 : 1 } function T(e, { plugins: t }) { function n(t, n) { return RegExp(g(t), "m" + (e.case\_insensitive ? "i" : "") + (n ? "g" : "")) } class i { constructor() { this.matchIndexes = {}, this.regexes = \[\], this.matchAt = 1, this.position = 0 } addRule(e, t) { t.position = this.position++, this.matchIndexes\[this.matchAt\] = t, this.regexes.push(\[t, e\]), this.matchAt += (e => RegExp(e.toString() + "|").exec("").length - 1)(e) + 1 } compile() { 0 === this.regexes.length && (this.exec = () => null) ; const e = this.regexes.map((e => e\[1\])); this.matcherRe = n(((e, t = "|") => { let n = 0 ; return e.map((e => { n += 1; const t = n; let i = g(e), s = ""; for (; i.length > 0;) { const e = u.exec(i); if (!e) { s += i; break } s += i.substring(0, e.index), i = i.substring(e.index + e\[0\].length), "\\\\" === e\[0\]\[0\] && e\[1\] ? s += "\\\\" + (Number(e\[1\]) + t) : (s += e\[0\], "(" === e\[0\] && n++) } return s })).map((e => \`(${e})\`)).join(t) })(e), !0), this.lastIndex = 0 } exec(e) { this.matcherRe.lastIndex = this.lastIndex; const t = this.matcherRe.exec(e) ; if (!t) return null ; const n = t.findIndex(((e, t) => t > 0 && void 0 !== e)), i = this.matchIndexes\[n\] ; return t.splice(0, n), Object.assign(t, i) } } class s { constructor() { this.rules = \[\], this.multiRegexes = \[\], this.count = 0, this.lastIndex = 0, this.regexIndex = 0 } getMatcher(e) { if (this.multiRegexes\[e\]) return this.multiRegexes\[e\]; const t = new i ; return this.rules.slice(e).forEach(((\[e, n\]) => t.addRule(e, n))), t.compile(), this.multiRegexes\[e\] = t, t } resumingScanAtSamePosition() { return 0 !== this.regexIndex } considerAll() { this.regexIndex = 0 } addRule(e, t) { this.rules.push(\[e, t\]), "begin" === t.type && this.count++ } exec(e) { const t = this.getMatcher(this.regexIndex); t.lastIndex = this.lastIndex ; let n = t.exec(e) ; if (this.resumingScanAtSamePosition()) if (n && n.index === this.lastIndex); else { const t = this.getMatcher(0); t.lastIndex = this.lastIndex + 1, n = t.exec(e) } return n && (this.regexIndex += n.position + 1, this.regexIndex === this.count && this.considerAll()), n } } if (e.compilerExtensions || (e.compilerExtensions = \[\]), e.contains && e.contains.includes("self")) throw Error("ERR: contains \`self\` is not supported at the top-level of a language. See documentation.") ; return e.classNameAliases = a(e.classNameAliases || {}), function t(i, r) { const l = i ; if (i.isCompiled) return l ;\[A\].forEach((e => e(i, r))), e.compilerExtensions.forEach((e => e(i, r))), i.\_\_beforeBegin = null, \[M, O, L\].forEach((e => e(i, r))), i.isCompiled = !0; let o = null ; if ("object" == typeof i.keywords && (o = i.keywords.$pattern, delete i.keywords.$pattern), i.keywords && (i.keywords = j(i.keywords, e.case\_insensitive)), i.lexemes && o) throw Error("ERR: Prefer \`keywords.$pattern\` to \`mode.lexemes\`, BOTH are not allowed. (see mode reference) ") ; return o = o || i.lexemes || /\\w+/, l.keywordPatternRe = n(o, !0), r && (i.begin || (i.begin = /\\B|\\b/), l.beginRe = n(i.begin), i.endSameAsBegin && (i.end = i.begin), i.end || i.endsWithParent || (i.end = /\\B|\\b/), i.end && (l.endRe = n(i.end)), l.terminatorEnd = g(i.end) || "", i.endsWithParent && r.terminatorEnd && (l.terminatorEnd += (i.end ? "|" : "") + r.terminatorEnd)), i.illegal && (l.illegalRe = n(i.illegal)), i.contains || (i.contains = \[\]), i.contains = \[\].concat(...i.contains.map((e => (e => (e.variants && !e.cachedVariants && (e.cachedVariants = e.variants.map((t => a(e, { variants: null }, t)))), e.cachedVariants ? e.cachedVariants : S(e) ? a(e, { starts: e.starts ? a(e.starts) : null }) : Object.isFrozen(e) ? a(e) : e))("self" === e ? i : e)))), i.contains.forEach((e => { t(e, l) })), i.starts && t(i.starts, r), l.matcher = (e => { const t = new s ; return e.contains.forEach((e => t.addRule(e.begin, { rule: e, type: "begin" }))), e.terminatorEnd && t.addRule(e.terminatorEnd, { type: "end" }), e.illegal && t.addRule(e.illegal, { type: "illegal" }), t })(l), l }(e) } function S(e) { return !!e && (e.endsWithParent || S(e.starts)) } function P(e) { const t = { props: \["language", "code", "autodetect"\], data: () => ({ detectedLanguage: "", unknownLanguage: !1 }), computed: { className() { return this.unknownLanguage ? "" : "hljs " + this.detectedLanguage }, highlighted() { if (!this.autoDetect && !e.getLanguage(this.language)) return console.warn(\`The language "${this.language}" you specified could not be found.\`), this.unknownLanguage = !0, s(this.code); let t = {} ; return this.autoDetect ? (t = e.highlightAuto(this.code), this.detectedLanguage = t.language) : (t = e.highlight(this.language, this.code, this.ignoreIllegals), this.detectedLanguage = this.language), t.value }, autoDetect() { return !(this.language && (e = this.autodetect, !e && "" !== e)); var e }, ignoreIllegals: () => !0 }, render(e) { return e("pre", {}, \[e("code", { class: this.className, domProps: { innerHTML: this.highlighted } })\]) } }; return { Component: t, VuePlugin: { install(e) { e.component("highlightjs", t) } } } } const D = { "after:highlightElement": ({ el: e, result: t, text: n }) => { const i = H(e) ; if (!i.length) return; const a = document.createElement("div") ; a.innerHTML = t.value, t.value = ((e, t, n) => { let i = 0, a = ""; const r = \[\]; function l() { return e.length && t.length ? e\[0\].offset !== t\[0\].offset ? e\[0\].offset < t\[0\].offset ? e : t : "start" === t\[0\].event ? e : t : e.length ? e : t } function o(e) { a += "<" + C(e) + \[\].map.call(e.attributes, (function (e) { return " " + e.nodeName + '="' + s(e.value) + '"' })).join("") + ">" } function c(e) { a += "</" + C(e) + ">" } function g(e) { ("start" === e.event ? o : c)(e.node) } for (; e.length || t.length;) { let t = l() ; if (a += s(n.substring(i, t\[0\].offset)), i = t\[0\].offset, t === e) { r.reverse().forEach(c) ; do { g(t.splice(0, 1)\[0\]), t = l() } while (t === e && t.length && t\[0\].offset === i) ; r.reverse().forEach(o) } else "start" === t\[0\].event ? r.push(t\[0\].node) : r.pop(), g(t.splice(0, 1)\[0\]) } return a + s(n.substr(i)) })(i, H(a), n) } }; function C(e) { return e.nodeName.toLowerCase() } function H(e) { const t = \[\]; return function e(n, i) { for (let s = n.firstChild; s; s = s.nextSibling)3 === s.nodeType ? i += s.nodeValue.length : 1 === s.nodeType && (t.push({ event: "start", offset: i, node: s }), i = e(s, i), C(s).match(/br|hr|img|input/) || t.push({ event: "stop", offset: i, node: s })); return i }(e, 0), t } const $ = e => { console.error(e) }, U = (e, ...t) => { console.log("WARN: " + e, ...t) }, z = (e, t) => { console.log(\`Deprecated as of ${e}. ${t}\`) }, K = s, G = a, V = Symbol("nomatch") ; return (e => { const n = Object.create(null), s = Object.create(null), a = \[\]; let r = !0 ; const l = /(^(<\[^>\]+>|\\t|)+|\\n)/gm, o = "Could not find the language '{}', did you forget to load/include a language module?", g = { disableAutodetect: !0, name: "Plain text", contains: \[\] }; let u = { noHighlightRe: /^(no-?highlight)$/i, languageDetectRe: /\\blang(?:uage)?-(\[\\w-\]+)\\b/i, classPrefix: "hljs-", tabReplace: null, useBR: !1, languages: null, \_\_emitter: c }; function h(e) { return u.noHighlightRe.test(e) } function d(e, t, n, i) { let s = "", a = "" ; "object" == typeof t ? (s = e, n = t.ignoreIllegals, a = t.language, i = void 0) : (z("10.7.0", "highlight(lang, code, ...args) has been deprecated."), z("10.7.0", "Please use highlight(code, options) instead.\\nhttps://github.com/highlightjs/highlight.js/issues/2277"), a = e, s = t); const r = { code: s, language: a }; M("before:highlight", r) ; const l = r.result ? r.result : f(r.language, r.code, n, i) ; return l.code = r.code, M("after:highlight", l), l } function f(e, t, s, l) { function c(e, t) { const n = v.case\_insensitive ? t\[0\].toLowerCase() : t\[0\] ; return Object.prototype.hasOwnProperty.call(e.keywords, n) && e.keywords\[n\] } function g() { null != R.subLanguage ? (() => { if ("" === M) return; let e = null ; if ("string" == typeof R.subLanguage) { if (!n\[R.subLanguage\]) return void k.addText(M) ; e = f(R.subLanguage, M, !0, \_\[R.subLanguage\]), \_\[R.subLanguage\] = e.top } else e = p(M, R.subLanguage.length ? R.subLanguage : null) ; R.relevance > 0 && (O += e.relevance), k.addSublanguage(e.emitter, e.language) })() : (() => { if (!R.keywords) return void k.addText(M); let e = 0 ; R.keywordPatternRe.lastIndex = 0; let t = R.keywordPatternRe.exec(M), n = ""; for (; t;) { n += M.substring(e, t.index); const i = c(R, t); if (i) { const \[e, s\] = i ; if (k.addText(n), n = "", O += s, e.startsWith("\_")) n += t\[0\]; else { const n = v.classNameAliases\[e\] || e; k.addKeyword(t\[0\], n) } } else n += t\[0\] ; e = R.keywordPatternRe.lastIndex, t = R.keywordPatternRe.exec(M) } n += M.substr(e), k.addText(n) })(), M = "" } function h(e) { return e.className && k.openNode(v.classNameAliases\[e.className\] || e.className), R = Object.create(e, { parent: { value: R } }), R } function d(e, t, n) { let s = ((e, t) => { const n = e && e.exec(t); return n && 0 === n.index })(e.endRe, n); if (s) { if (e\["on:end"\]) { const n = new i(e); e\["on:end"\](t, n), n.isMatchIgnored && (s = !1) } if (s) { for (; e.endsParent && e.parent;)e = e.parent; return e } } if (e.endsWithParent) return d(e.parent, t, n) } function m(e) { return 0 === R.matcher.regexIndex ? (M += e\[0\], 1) : (I = !0, 0) } function b(e) { const n = e\[0\], i = t.substr(e.index), s = d(R, e, i); if (!s) return V; const a = R ; a.skip ? M += n : (a.returnEnd || a.excludeEnd || (M += n), g(), a.excludeEnd && (M = n)); do { R.className && k.closeNode(), R.skip || R.subLanguage || (O += R.relevance), R = R.parent } while (R !== s.parent) ; return s.starts && (s.endSameAsBegin && (s.starts.endRe = s.endRe), h(s.starts)), a.returnEnd ? 0 : n.length } let E = {}; function x(n, a) { const l = a && a\[0\] ; if (M += n, null == l) return g(), 0 ; if ("begin" === E.type && "end" === a.type && E.index === a.index && "" === l) { if (M += t.slice(a.index, a.index + 1), !r) { const t = Error("0 width match regex") ; throw t.languageName = e, t.badRule = E.rule, t } return 1 } if (E = a, "begin" === a.type) return function (e) { const t = e\[0\], n = e.rule, s = new i(n), a = \[n.\_\_beforeBegin, n\["on:begin"\]\] ; for (const n of a) if (n && (n(e, s), s.isMatchIgnored)) return m(t) ; return n && n.endSameAsBegin && (n.endRe = RegExp(t.replace(/\[-/\\\\^$\*+?.()|\[\\\]{}\]/g, "\\\\$&"), "m")), n.skip ? M += t : (n.excludeBegin && (M += t), g(), n.returnBegin || n.excludeBegin || (M = t)), h(n), n.returnBegin ? 0 : t.length }(a) ; if ("illegal" === a.type && !s) { const e = Error('Illegal lexeme "' + l + '" for mode "' + (R.className || "<unnamed>") + '"') ; throw e.mode = R, e } if ("end" === a.type) { const e = b(a); if (e !== V) return e } if ("illegal" === a.type && "" === l) return 1 ; if (L > 1e5 && L > 3 \* a.index) throw Error("potential infinite loop, way more iterations than matches") ; return M += l, l.length } const v = N(e) ; if (!v) throw $(o.replace("{}", e)), Error('Unknown language: "' + e + '"') ; const w = T(v, { plugins: a }); let y = "", R = l || w; const \_ = {}, k = new u.\_\_emitter(u); (() => { const e = \[\]; for (let t = R; t !== v; t = t.parent)t.className && e.unshift(t.className) ; e.forEach((e => k.openNode(e))) })(); let M = "", O = 0, A = 0, L = 0, I = !1; try { for (R.matcher.considerAll(); ;) { L++, I ? I = !1 : R.matcher.considerAll(), R.matcher.lastIndex = A ; const e = R.matcher.exec(t); if (!e) break; const n = x(t.substring(A, e.index), e) ; A = e.index + n } return x(t.substr(A)), k.closeAllNodes(), k.finalize(), y = k.toHTML(), { relevance: Math.floor(O), value: y, language: e, illegal: !1, emitter: k, top: R } } catch (n) { if (n.message && n.message.includes("Illegal")) return { illegal: !0, illegalBy: { msg: n.message, context: t.slice(A - 100, A + 100), mode: n.mode }, sofar: y, relevance: 0, value: K(t), emitter: k }; if (r) return { illegal: !1, relevance: 0, value: K(t), emitter: k, language: e, top: R, errorRaised: n }; throw n } } function p(e, t) { t = t || u.languages || Object.keys(n); const i = (e => { const t = { relevance: 0, emitter: new u.\_\_emitter(u), value: K(e), illegal: !1, top: g } ; return t.emitter.addText(e), t })(e), s = t.filter(N).filter(k).map((t => f(t, e, !1))) ; s.unshift(i); const a = s.sort(((e, t) => { if (e.relevance !== t.relevance) return t.relevance - e.relevance ; if (e.language && t.language) { if (N(e.language).supersetOf === t.language) return 1 ; if (N(t.language).supersetOf === e.language) return -1 } return 0 })), \[r, l\] = a, o = r ; return o.second\_best = l, o } const m = { "before:highlightElement": ({ el: e }) => { u.useBR && (e.innerHTML = e.innerHTML.replace(/\\n/g, "").replace(/<br\[ /\]\*>/g, "\\n")) }, "after:highlightElement": ({ result: e }) => { u.useBR && (e.value = e.value.replace(/\\n/g, "<br>")) } }, b = /^(<\[^>\]+>|\\t)+/gm, E = { "after:highlightElement": ({ result: e }) => { u.tabReplace && (e.value = e.value.replace(b, (e => e.replace(/\\t/g, u.tabReplace)))) } } ; function x(e) { let t = null; const n = (e => { let t = e.className + " " ; t += e.parentNode ? e.parentNode.className : ""; const n = u.languageDetectRe.exec(t) ; if (n) { const t = N(n\[1\]) ; return t || (U(o.replace("{}", n\[1\])), U("Falling back to no-highlight mode for this block.", e)), t ? n\[1\] : "no-highlight" } return t.split(/\\s+/).find((e => h(e) || N(e))) })(e) ; if (h(n)) return; M("before:highlightElement", { el: e, language: n }), t = e ; const i = t.textContent, a = n ? d(i, { language: n, ignoreIllegals: !0 }) : p(i) ; M("after:highlightElement", { el: e, result: a, text: i }), e.innerHTML = a.value, ((e, t, n) => { const i = t ? s\[t\] : n ; e.classList.add("hljs"), i && e.classList.add(i) })(e, n, a.language), e.result = { language: a.language, re: a.relevance, relavance: a.relevance }, a.second\_best && (e.second\_best = { language: a.second\_best.language, re: a.second\_best.relevance, relavance: a.second\_best.relevance }) } const v = () => { v.called || (v.called = !0, z("10.6.0", "initHighlighting() is deprecated. Use highlightAll() instead."), document.querySelectorAll("pre code").forEach(x)) }; let w = !1; function y() { "loading" !== document.readyState ? document.querySelectorAll("pre code").forEach(x) : w = !0 } function N(e) { return e = (e || "").toLowerCase(), n\[e\] || n\[s\[e\]\] } function R(e, { languageName: t }) { "string" == typeof e && (e = \[e\]), e.forEach((e => { s\[e.toLowerCase()\] = t })) } function k(e) { const t = N(e) ; return t && !t.disableAutodetect } function M(e, t) { const n = e; a.forEach((e => { e\[n\] && e\[n\](t) })) } "undefined" != typeof window && window.addEventListener && window.addEventListener("DOMContentLoaded", (() => { w && y() }), !1), Object.assign(e, { highlight: d, highlightAuto: p, highlightAll: y, fixMarkup: e => { return z("10.2.0", "fixMarkup will be removed entirely in v11.0"), z("10.2.0", "Please see https://github.com/highlightjs/highlight.js/issues/2534"), t = e, u.tabReplace || u.useBR ? t.replace(l, (e => "\\n" === e ? u.useBR ? "<br>" : e : u.tabReplace ? e.replace(/\\t/g, u.tabReplace) : e)) : t ; var t }, highlightElement: x, highlightBlock: e => (z("10.7.0", "highlightBlock will be removed entirely in v12.0"), z("10.7.0", "Please use highlightElement now."), x(e)), configure: e => { e.useBR && (z("10.3.0", "'useBR' will be removed entirely in v11.0"), z("10.3.0", "Please see https://github.com/highlightjs/highlight.js/issues/2559")), u = G(u, e) }, initHighlighting: v, initHighlightingOnLoad: () => { z("10.6.0", "initHighlightingOnLoad() is deprecated. Use highlightAll() instead."), w = !0 }, registerLanguage: (t, i) => { let s = null; try { s = i(e) } catch (e) { if ($("Language definition for '{}' could not be registered.".replace("{}", t)), !r) throw e; $(e), s = g } s.name || (s.name = t), n\[t\] = s, s.rawDefinition = i.bind(null, e), s.aliases && R(s.aliases, { languageName: t }) }, unregisterLanguage: e => { delete n\[e\] ; for (const t of Object.keys(s)) s\[t\] === e && delete s\[t\] }, listLanguages: () => Object.keys(n), getLanguage: N, registerAliases: R, requireLanguage: e => { z("10.4.0", "requireLanguage will be removed entirely in v11."), z("10.4.0", "Please see https://github.com/highlightjs/highlight.js/pull/2844") ; const t = N(e); if (t) return t ; throw Error("The '{}' language is required, but not loaded.".replace("{}", e)) }, autoDetection: k, inherit: G, addPlugin: e => { (e => { e\["before:highlightBlock"\] && !e\["before:highlightElement"\] && (e\["before:highlightElement"\] = t => { e\["before:highlightBlock"\](Object.assign({ block: t.el }, t)) }), e\["after:highlightBlock"\] && !e\["after:highlightElement"\] && (e\["after:highlightElement"\] = t => { e\["after:highlightBlock"\](Object.assign({ block: t.el }, t)) }) })(e), a.push(e) }, vuePlugin: P(e).VuePlugin }), e.debugMode = () => { r = !1 }, e.safeMode = () => { r = !0 }, e.versionString = "10.7.1"; for (const e in \_) "object" == typeof \_\[e\] && t(\_\[e\]) ; return Object.assign(e, \_), e.addPlugin(m), e.addPlugin(D), e.addPlugin(E), e })({}) }(); "object" == typeof exports && "undefined" != typeof module && (module.exports = hljs); hljs.registerLanguage("ruby", (() => { "use strict"; function e(...e) { return e.map((e => { return (n = e) ? "string" == typeof n ? n : n.source : null; var n })).join("") } return n => { const a = "(\[a-zA-Z\_\]\\\\w\*\[!?=\]?|\[-+~\]@|<<|>>|=~|===?|<=>|\[<>\]=?|\\\\\*\\\\\*|\[-/+%^&\*~\`|\]|\\\\\[\\\\\]=?)", i = { keyword: "and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr\_reader attr\_writer attr\_accessor \_\_FILE\_\_", built\_in: "proc lambda", literal: "true false nil" }, s = { className: "doctag", begin: "@\[A-Za-z\]+" }, r = { begin: "#<", end: ">" }, b = \[n.COMMENT("#", "$", { contains: \[s\] }), n.COMMENT("^=begin", "^=end", { contains: \[s\], relevance: 10 }), n.COMMENT("^\_\_END\_\_", "\\\\n$")\], c = { className: "subst", begin: /#\\{/, end: /\\}/, keywords: i }, t = { className: "string", contains: \[n.BACKSLASH\_ESCAPE, c\], variants: \[{ begin: /'/, end: /'/ }, { begin: /"/, end: /"/ }, { begin: /\`/, end: /\`/ }, { begin: /%\[qQwWx\]?\\(/, end: /\\)/ }, { begin: /%\[qQwWx\]?\\\[/, end: /\\\]/ }, { begin: /%\[qQwWx\]?\\{/, end: /\\}/ }, { begin: /%\[qQwWx\]?</, end: />/ }, { begin: /%\[qQwWx\]?\\//, end: /\\// }, { begin: /%\[qQwWx\]?%/, end: /%/ }, { begin: /%\[qQwWx\]?-/, end: /-/ }, { begin: /%\[qQwWx\]?\\|/, end: /\\|/ }, { begin: /\\B\\?(\\\\\\d{1,3})/ }, { begin: /\\B\\?(\\\\x\[A-Fa-f0-9\]{1,2})/ }, { begin: /\\B\\?(\\\\u\\{?\[A-Fa-f0-9\]{1,6}\\}?)/ }, { begin: /\\B\\?(\\\\M-\\\\C-|\\\\M-\\\\c|\\\\c\\\\M-|\\\\M-|\\\\C-\\\\M-)\[\\x20-\\x7e\]/ }, { begin: /\\B\\?\\\\(c|C-)\[\\x20-\\x7e\]/ }, { begin: /\\B\\?\\\\?\\S/ }, { begin: /<<\[-~\]?'?(\\w+)\\n(?:\[^\\n\]\*\\n)\*?\\s\*\\1\\b/, returnBegin: !0, contains: \[{ begin: /<<\[-~\]?'?/ }, n.END\_SAME\_AS\_BEGIN({ begin: /(\\w+)/, end: /(\\w+)/, contains: \[n.BACKSLASH\_ESCAPE, c\] })\] }\] }, g = "\[0-9\](\_?\[0-9\])\*", d = { className: "number", relevance: 0, variants: \[{ begin: \`\\\\b(\[1-9\](\_?\[0-9\])\*|0)(\\\\.(${g}))?(\[eE\]\[+-\]?(${g})|r)?i?\\\\b\` }, { begin: "\\\\b0\[dD\]\[0-9\](\_?\[0-9\])\*r?i?\\\\b" }, { begin: "\\\\b0\[bB\]\[0-1\](\_?\[0-1\])\*r?i?\\\\b" }, { begin: "\\\\b0\[oO\]\[0-7\](\_?\[0-7\])\*r?i?\\\\b" }, { begin: "\\\\b0\[xX\]\[0-9a-fA-F\](\_?\[0-9a-fA-F\])\*r?i?\\\\b" }, { begin: "\\\\b0(\_?\[0-7\])+r?i?\\\\b" }\] }, l = { className: "params", begin: "\\\\(", end: "\\\\)", endsParent: !0, keywords: i }, o = \[t, { className: "class", beginKeywords: "class module", end: "$|;", illegal: /=/, contains: \[n.inherit(n.TITLE\_MODE, { begin: "\[A-Za-z\_\]\\\\w\*(::\\\\w+)\*(\\\\?|!)?" }), { begin: "<\\\\s\*", contains: \[{ begin: "(" + n.IDENT\_RE + "::)?" + n.IDENT\_RE, relevance: 0 }\] }\].concat(b) }, { className: "function", begin: e(/def\\s+/, (\_ = a + "\\\\s\*(\\\\(|;|$)", e("(?=", \_, ")"))), relevance: 0, keywords: "def", end: "$|;", contains: \[n.inherit(n.TITLE\_MODE, { begin: a }), l\].concat(b) }, { begin: n.IDENT\_RE + "::" }, { className: "symbol", begin: n.UNDERSCORE\_IDENT\_RE + "(!|\\\\?)?:", relevance: 0 }, { className: "symbol", begin: ":(?!\\\\s)", contains: \[t, { begin: a }\], relevance: 0 }, d, { className: "variable", begin: "(\\\\$\\\\W)|((\\\\$|@@?)(\\\\w+))(?=\[^@$?\])(?!\[A-Za-z\])(?!\[@$?'\])" }, { className: "params", begin: /\\|/, end: /\\|/, relevance: 0, keywords: i }, { begin: "(" + n.RE\_STARTERS\_RE + "|unless)\\\\s\*", keywords: "unless", contains: \[{ className: "regexp", contains: \[n.BACKSLASH\_ESCAPE, c\], illegal: /\\n/, variants: \[{ begin: "/", end: "/\[a-z\]\*" }, { begin: /%r\\{/, end: /\\}\[a-z\]\*/ }, { begin: "%r\\\\(", end: "\\\\)\[a-z\]\*" }, { begin: "%r!", end: "!\[a-z\]\*" }, { begin: "%r\\\\\[", end: "\\\\\]\[a-z\]\*" }\] }\].concat(r, b), relevance: 0 }\].concat(r, b); var \_; c.contains = o, l.contains = o ; const E = \[{ begin: /^\\s\*=>/, starts: { end: "$", contains: o } }, { className: "meta", begin: "^(\[>?\]>|\[\\\\w#\]+\\\\(\\\\w+\\\\):\\\\d+:\\\\d+>|(\\\\w+-)?\\\\d+\\\\.\\\\d+\\\\.\\\\d+(p\\\\d+)?\[^\\\\d\]\[^>\]+>)(?=\[ \])", starts: { end: "$", contains: o } }\]; return b.unshift(r), { name: "Ruby", aliases: \["rb", "gemspec", "podspec", "thor", "irb"\], keywords: i, illegal: /\\/\\\*/, contains: \[n.SHEBANG({ binary: "ruby" })\].concat(E).concat(b).concat(o) } } })()); hljs.registerLanguage("yaml", (() => { "use strict"; return e => { var n = "true false yes no null", a = "\[\\\\w#;/?:@&=+$,.~\*'()\[\\\\\]\]+", s = { className: "string", relevance: 0, variants: \[{ begin: /'/, end: /'/ }, { begin: /"/, end: /"/ }, { begin: /\\S+/ }\], contains: \[e.BACKSLASH\_ESCAPE, { className: "template-variable", variants: \[{ begin: /\\{\\{/, end: /\\}\\}/ }, { begin: /%\\{/, end: /\\}/ }\] }\] }, i = e.inherit(s, { variants: \[{ begin: /'/, end: /'/ }, { begin: /"/, end: /"/ }, { begin: /\[^\\s,{}\[\\\]\]+/ }\] }), l = { end: ",", endsWithParent: !0, excludeEnd: !0, keywords: n, relevance: 0 }, t = { begin: /\\{/, end: /\\}/, contains: \[l\], illegal: "\\\\n", relevance: 0 }, g = { begin: "\\\\\[", end: "\\\\\]", contains: \[l\], illegal: "\\\\n", relevance: 0 }, b = \[{ className: "attr", variants: \[{ begin: "\\\\w\[\\\\w :\\\\/.-\]\*:(?=\[ \\t\]|$)" }, { begin: '"\\\\w\[\\\\w :\\\\/.-\]\*":(?=\[ \\t\]|$)' }, { begin: "'\\\\w\[\\\\w :\\\\/.-\]\*':(?=\[ \\t\]|$)" }\] }, { className: "meta", begin: "^---\\\\s\*$", relevance: 10 }, { className: "string", begin: "\[\\\\|>\](\[1-9\]?\[+-\])?\[ \]\*\\\\n( +)\[^ \]\[^\\\\n\]\*\\\\n(\\\\2\[^\\\\n\]+\\\\n?)\*" }, { begin: "<%\[%=-\]?", end: "\[%-\]?%>", subLanguage: "ruby", excludeBegin: !0, excludeEnd: !0, relevance: 0 }, { className: "type", begin: "!\\\\w+!" + a }, { className: "type", begin: "!<" + a + ">" }, { className: "type", begin: "!" + a }, { className: "type", begin: "!!" + a }, { className: "meta", begin: "&" + e.UNDERSCORE\_IDENT\_RE + "$" }, { className: "meta", begin: "\\\\\*" + e.UNDERSCORE\_IDENT\_RE + "$" }, { className: "bullet", begin: "-(?=\[ \]|$)", relevance: 0 }, e.HASH\_COMMENT\_MODE, { beginKeywords: n, keywords: { literal: n } }, { className: "number", begin: "\\\\b\[0-9\]{4}(-\[0-9\]\[0-9\]){0,2}(\[Tt \\\\t\]\[0-9\]\[0-9\]?(:\[0-9\]\[0-9\]){2})?(\\\\.\[0-9\]\*)?(\[ \\\\t\])\*(Z|\[-+\]\[0-9\]\[0-9\]?(:\[0-9\]\[0-9\])?)?\\\\b" }, { className: "number", begin: e.C\_NUMBER\_RE + "\\\\b", relevance: 0 }, t, g, s\], r = \[...b\] ; return r.pop(), r.push(i), l.contains = r, { name: "YAML", case\_insensitive: !0, aliases: \["yml"\], contains: b } } })()); document.addEventListener('DOMContentLoaded', (event) => { document.querySelectorAll('pre code').forEach((block) => { hljs.highlightBlock(block); }); $('.tabs\_\_item.maintab').on('click', (el) => { var selectedTab = $(el.currentTarget).attr('aria-controls'); // Toggle the tab visibility document.querySelectorAll('.tabs\_\_item.maintab').forEach((tab) => { $(tab).attr('aria-selected', tab.id.startsWith(selectedTab)); }); // Toggle the panel visibility document.querySelectorAll('.tabs\_\_panel.maintab').forEach((panel) => { panel.hidden = panel.id.startsWith(selectedTab) ? false : true; }); }); $('.tabs\_\_item.reporttab').on('click', (el) => { var selectedTab = $(el.currentTarget).attr('aria-controls'); // Toggle the tab visibility document.querySelectorAll('.tabs\_\_item.reporttab').forEach((tab) => { $(tab).attr('aria-selected', tab.id.startsWith(selectedTab)); }); // Toggle the panel visibility document.querySelectorAll('.tabs\_\_panel.reporttab').forEach((panel) => { panel.hidden = panel.id.startsWith(selectedTab) ? false : true; }); }); }); function switchToTab(tabName, contentId) { $('#' + tabName).click(); }; const copyContent = function (contentId) { const copyText = document.getElementById("asyncapiCode").textContent; const textArea = document.createElement('textarea'); textArea.textContent = copyText; document.body.append(textArea); textArea.select(); document.execCommand("copy"); textArea.remove(); };

div.tabs\_\_item\[role="tab"\]:not(:last-child), li.fake-tabs\_\_item:not(:last-child) { margin-right: 33px; } <!-- .content .note { background-color: #fbebee; display: inline-flex; } .content .note>span { display: inline-block; padding: 12px 18px; } .content .note>.color-crimson { background-color: #e43137; color: #FFF; } .content .dash { list-style-type: none; margin: 0; padding: 0 0 0 15px; } .content .dash>li { padding: 10px 0; text-indent: -4px; } .content .dash>li:before { content: "-"; display: inline-block; text-indent: -10px; } .content .useful-links { list-style-type: none; padding: 0; } .content .useful-links li { padding: 5px 0; } .content .other-useful-links-container { display: flex; } .content .other-useful-links-container>div:first-child { margin-right: 120px; } .asyncapiContract { justify-content: space-between; } .flex-gap { margin: 10px; } h3 { max-width: 30em !important; } table { width: 46em; min-width: auto; } @media only screen and (max-width: 500px) { .content .other-useful-links-container { display: block; } } /\* Google Code style (c) Aahan Krish <geekpanth3r@gmail.com> \*/ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: black; } .hljs-comment, .hljs-quote { color: #800; } .hljs-keyword, .hljs-selector-tag, .hljs-section, .hljs-title, .hljs-name { color: #008; } .hljs-variable, .hljs-template-variable { color: #660; } .hljs-string, .hljs-selector-attr, .hljs-selector-pseudo, .hljs-regexp { color: #080; } .hljs-literal, .hljs-symbol, .hljs-bullet, .hljs-meta, .hljs-number, .hljs-link { color: #066; } .hljs-title, .hljs-doctag, .hljs-type, .hljs-attr, .hljs-built\_in, .hljs-builtin-name, .hljs-params { color: #606; } .hljs-attribute, .hljs-subst { color: #000; } .hljs-formula { background-color: #eee; font-style: italic; } .hljs-selector-id, .hljs-selector-class { color: #9B703F } .hljs-addition { background-color: #baeeba; } .hljs-deletion { background-color: #ffc8bd; } .hljs-doctag, .hljs-strong { font-weight: bold; } .hljs-emphasis { font-style: italic; } -->

## Interface Performance

Access the latest performance and availability metrics for our API interfaces: 

*   [API Status](/develop/guides/regulated-third-party-providers-tpp/api-status)
*   [Performance and Availability Metrics](/develop/guides/regulated-third-party-providers-tpp/interface-performance)

## FAQs

The FAQs in this section address some common questions about TTPs' use of these APIs.

*   Why did my `registerClient` call fail?
    
    There are several possible reasons:
    
    *   You are not licensed as a TPP.
    *   A valid redirect URI was not provided.
*   I am a TPP, but do not have an eIDAS Qualified Website Authentication Certificate (QWAC). Can I register my client with eBay using `registerClient` without having it?
    
    No. You must have a valid eIDAS Qualified Website Authentication Certificate (QWAC) in order to register a client with eBay.
    
    **NOTE:** eBay does not support Qualified Electronic Seal (QSEAL) certificates.
    
*   Is there an environment where I can do testing of my code?
    
    Yes. eBay provides a Sandbox environment for testing purposes. Once your application has been registered with eBay and has obtained all necessary client details and tokens for the Sandbox environment, you may use the Sandbox environment to test your code. Refer to [Using Sandbox for testing](https://developer.ebay.com/develop/guides/regulated-third-party-providers-tpp/faqs#sb) for complete information.
    
*   Unlike other eBay APIs, the [Client Registration API](https://developer.ebay.com/api-docs/developer/client-registration/overview.html) does not return numeric error codes. Why is this?
    
    The Client Registration API is based on, and conforms with, [RFC 7591 - OAuth 2.0 Dynamic Client Registration Protocol](https://datatracker.ietf.org/doc/html/rfc7591) which does not support numeric error codes, only text-based error messages. Therefore, numeric error codes are not supported by this API.
    
*   `registerClient` returns `redirect_uris`. Why are they not formatted as typical URIs, and how do I use them?
    
    Instead of a URL, the OAuth flow requires a custom `redirect_uri` value that eBay generates and assigns to your application. Refer to [Getting your redirect\_uri value](https://developer.ebay.com/api-docs/static/oauth-redirect-uri.html) for additional information about redirect uris.
    
*   I don't see an answer to my question. Whom should I contact for client registration related questions?
    
    Please contact [eBay Customer Support](https://www.ebay.com/help/home).

