# Get KYC Widget URL Source: https://docs.payments.sardine.ai/api_reference/identity/consent-widget/get-kyc-widget-url /api_reference/identity.yaml post /identity/consents/widget Generates a hosted widget URL that you redirect your user to (or embed as an iframe) to complete KYC or share an existing verified identity. **Flows** - `kyc_input` *(default)* — The user verifies their identity from scratch in the Sardine hosted widget (passport, driver's license, liveness check, etc.). Use this for new users or when you need specific additional verification steps. - `kyc_sharing` — The user consents to share an identity already verified by another Sardine partner. This produces near-instant approval for returning Sardine users. **Scopes** Control which data the widget will collect or share: - `profile` — Basic personal information (name, DOB, address, email, phone) - `doc_kyc` — Government ID document scan + liveness check - `liveness` — Liveness check only - `ssn` — Social Security Number (US users) **After the Widget** When the user completes the flow the widget redirects to `successUrl`. Call `GET /identity/entities/{customerId}` to retrieve the verified data. # Create Customer Source: https://docs.payments.sardine.ai/api_reference/identity/customer-management/create-customer /api_reference/identity.yaml post /identity/entities Creates a new identity record for a customer. The phone number must be unique per client. Returns the Sardine `customerId` which is used in all subsequent identity API calls. # Get Customer Identity Source: https://docs.payments.sardine.ai/api_reference/identity/customer-management/get-customer-identity /api_reference/identity.yaml get /identity/entities/{customerId} Returns the verified identity data for a customer, including profile, document data, and document images. The response is gated by the user's consent: - `profile` fields are returned when the `profile` scope was consented - `documentKyc` and `documentData` are returned when the `doc_kyc` scope was consented If the identity belongs to another client, a valid `kyc_sharing` consent record (consented and not revoked) must exist. # Search Customer Source: https://docs.payments.sardine.ai/api_reference/identity/customer-management/search-customer /api_reference/identity.yaml post /identity/entities/search Looks up a customer by phone number. Use this to check whether a customer already exists before calling `POST /identity/entities`. # Send bank information Source: https://docs.payments.sardine.ai/api_reference/nft/banks/send-bank-information /api_reference/nft.yaml get /banks/transactions Simply populate the appropriate field in the plaidData object. Make sure to fill in the correct field corresponding to the correct Plaid API endpoint. For example, if you call the Plaid transactions API, you should set plaidData.transactionsResponse to be the JSON string containing the response. Note that the response fields in plaidData are all optional and you may populate as many or few as you would like, as long as an authResponse is sent at least once per account. Important note: You must provide an authResponse at least once per customer bank account so that we can store the mapping from bank account to Plaid account ID. # Create Payout Source: https://docs.payments.sardine.ai/api_reference/nft/create-payout /api_reference/nft.yaml post /payouts Create a Payout where Sardine will send crypto to specified wallet(s) in specified cryptocurrencies. A Payout can be created associated with a corresponding fiat order (where Sardine has also done the fiat processing) or without one (where Sardine does not do the fiat component). To trigger Payouts without the fiat processing being done by Sardine, contact your Integration team. # Get Customers Source: https://docs.payments.sardine.ai/api_reference/nft/customers/get-customers /api_reference/nft.yaml get /customers Fetches list of all customers. Can be filtered by passing `customerId` # Post Customer Information Source: https://docs.payments.sardine.ai/api_reference/nft/customers/post-customer-information /api_reference/nft.yaml post /customers Send User information to Sardine to store theie information and create a risk profile # Fetch Payout Information Source: https://docs.payments.sardine.ai/api_reference/nft/fetch-payout-information /api_reference/nft.yaml get /payouts/{payout_id} Fetch payouts information by `order_id` or `payout_id` 1. By `order_id` Make a GET request to /payouts/order_id={} 2. By `payout_id` Make a GET request to /payouts/{payout_id} # Get fiat currencies Source: https://docs.payments.sardine.ai/api_reference/nft/get-fiat-currencies /api_reference/nft.yaml get /fiat-currencies List of fiat currencies supported by Sardine # Get Geocoverage Source: https://docs.payments.sardine.ai/api_reference/nft/get-geocoverage /api_reference/nft.yaml get /geo-coverage Get list of regions where Sardine is supported, separated by county and state regions # Get Order(s) Source: https://docs.payments.sardine.ai/api_reference/nft/get-orders /api_reference/nft.yaml get /orders Fetch information about an Order once its completed The `status` of an Order can be one of the following `Draft` - This is an open or ongoing order `Expired`* - The user didn't complete the transaction within the `expiration` time `Processed`* - The payment has been completed. `Declined`* - The transacation was declined, due to payment method issues `Cancelled`* - The transaction did not complete, which could be for a number of reasons, as outlined in the reason codes below. `Complete`* - The payment is complete and the crypto has been delivered to the user's wallet. A `txHash` will be present to denote successful on chain settlement. `Refunded` - The User's payment has been refunded to their original payment method ### For Smart Contract Integrations Orders might end up in `Cancelled` state, due to a number of reasons, which Sardine will share through a `reasonCode` parameter as part of an `error` object in the Order. After an Order has been Cancelled, it will move to the `Refunded` state The following reason codes might appear `NETF` - Network Failure `PRCC` - Price Change beyond threshold `RISD` - Risk Decline `NA` - NFT Not Available Events marked with an * can also be captured via event handlers on the frontend ### Fetching Orders Full list of Orders is obtained by making a call to the endpoint with no filters. You have multiple options of filtering orders 1. Filtering by `orderId` If a `redirect_url` was passed to the Sardine checkout (e.g. https://crytpoapp.com"), when then transaction is completed, Sardine will redirect the user to this url with an `order_id` appended i.e. https://cryptoapp.com?order_id=73103-erhed-317313 This `order_id` can then be used as a filter on this endpoint, this form https://api.sandbox.sardine.ai/v1/orders/3103-erhed-317313 2. Filtering by `referenceId` If a `referenceId` was passed in the call to create the `clientToken` for this call, it can now be used to filter for Orders that were created then. 3. Filtering by `startDate` and `endDate` If `startDate` or `endDate` are passed in YYYY-MM-DD format, the list of Orders will be filtered to those that were created in this range 4. Filtering by `externalUserId` # Fetch KYC Source: https://docs.payments.sardine.ai/api_reference/nft/identity/fetch-kyc /api_reference/nft.yaml get /identityDocuments/verifications/{id} Retrieve result of document verification # Add new Bank Account using aggregator token Source: https://docs.payments.sardine.ai/api_reference/nft/payment-method/add-new-bank-account-using-aggregator-token /api_reference/nft.yaml post /payment-method/ach Add new Bank Account to User. Currently, this can be done in one of two ways 1. Using a processor token from bank aggregator service like Plaid 2. Sending information about the user's bank account collected through a Plaid like service # Delete Bank Account Source: https://docs.payments.sardine.ai/api_reference/nft/payment-method/delete-bank-account /api_reference/nft.yaml delete /payment-method/ach Delete bank account with the corresponding bank account ID # Get Bank Account Source: https://docs.payments.sardine.ai/api_reference/nft/payment-method/get-bank-account /api_reference/nft.yaml get /payment-method/ach Get information about Bank Account object # Post Client Token Source: https://docs.payments.sardine.ai/api_reference/nft/post-client-token /api_reference/nft.yaml post /auth/client-tokens Exchange your `clientId` and `clientSecret` for a `clientToken` that can be be used in frontend code. `clientToken` will be unusable after the `expiresAt` time, which will normally be after 30 min. To try the request in the mock server on the right, substitute username for clientId and password for clientSecre # Update NFT Status Source: https://docs.payments.sardine.ai/api_reference/nft/update-nft-status /api_reference/nft.yaml get /orders/events # Update Order Source: https://docs.payments.sardine.ai/api_reference/nft/update-order /api_reference/nft.yaml post /orders/events # Get Enabled Tokens Source: https://docs.payments.sardine.ai/api_reference/onramp/coverage/get-enabled-tokens /api_reference/onramp.yaml get /enabled-tokens Fetch list of tokens supported. # Get Fiat Currencies Source: https://docs.payments.sardine.ai/api_reference/onramp/coverage/get-fiat-currencies /api_reference/onramp.yaml get /fiat-currencies List of fiat currencies supported by Sardine # Get Geocoverage Source: https://docs.payments.sardine.ai/api_reference/onramp/coverage/get-geocoverage /api_reference/onramp.yaml get /geo-coverage Get list of regions where Sardine is supported, separated by county and state regions # Get Supported Tokens Source: https://docs.payments.sardine.ai/api_reference/onramp/coverage/get-supported-tokens /api_reference/onramp.yaml get /supported-tokens Fetch list of tokens supported. # Create Offramp Order Source: https://docs.payments.sardine.ai/api_reference/onramp/order-execution/create-offramp-order /api_reference/onramp.yaml post /offramp This endpoint is used to initiate an offramp transaction, converting crypto to fiat and transferring funds to the user's connected payment method. # Create Onramp Order Source: https://docs.payments.sardine.ai/api_reference/onramp/order-execution/create-onramp-order /api_reference/onramp.yaml post /onramp This endpoint is used to initiate an onramp transaction, converting fiat to crypto and delivering the crypto to a destination wallet. # Get an Order by ID Source: https://docs.payments.sardine.ai/api_reference/onramp/order/get-an-order-by-id /api_reference/onramp.yaml get /orders/{orderId} Fetch information about an Order once its completed The `status` of an Order can be one of the following `Draft` - This is an open or ongoing order `Processed`* - The payment has been completed. `Declined`* - The transacation was declined, due to payment method issues `UserCustody` - Crypto purchased for user but is in Sardine's custodied wallet `Complete` - The payment is complete and the crypto has been delivered to the user's wallet. A `txHash` will be present to denote successful on chain settlement. `Expired` - Order expired before execution Events marked with an * can also be captured via event handlers on the frontend ### Fetching Orders Full list of Orders is obtained by making a call to the endpoint with no filters. You have multiple options of filtering orders **1. Filtering by `order_id`** If a `redirect_url` was passed to the Sardine checkout (e.g. https://crytpoapp.com"), when then transaction is completed, Sardine will redirect the user to this url with an `order_id` appended i.e. https://cryptoapp.com?order_id=73103-erhed-317313 This `order_id` can then be used as a filter on this endpoint E.g. `/v1/orders/491c113c-4485-47cd-b011-252068b753dc` **2. Filtering by `referenceId`** If a `referenceId` was passed in the call to create the `clientToken` for this call, it can now be used to filter for Orders that were created then. E.g. `/v1/orders?referenceId=42ead95db5aeb6c` **3. Filtering by `externalUserId`** If a `externalUserId` was passed in /auth/client-tokens, it can be used to filter for Orders with that ID. This is useful for associating transactions with a user **3. Filtering by `startDate` and `endDate`** If `startDate` or `endDate` are passed in YYYY-MM-DD format, the list of Orders will be filtered to those that were created in this range E.g. `/v1/orders?startDate=2022-08-01&endDate=2022-08-15` `paymentStatus` field within the `payment` object in the response can be - Draft - Pending For bank transfers, the value could be - Sent - Complete - Returned - Failed For card transactions, the value can be - Authorized - Captured - Declined - Pending3DS - Failure3DS - Voided # Get User Orders Source: https://docs.payments.sardine.ai/api_reference/onramp/order/get-user-orders /api_reference/onramp.yaml get /orders This endpoint retrieves the list of orders placed by the user, with optional filtering based on specific query parameters like userId. # Get Add Fiat Account Widget URL Source: https://docs.payments.sardine.ai/api_reference/onramp/payment-method/get-add-fiat-account-widget-url /api_reference/onramp.yaml get /payment-methods/widgetUrl This endpoint returns a URL where users can be redirected to connect external fiat payment methods, including credit/debit cards, bank accounts, and SEPA. # Get Payment Method information Source: https://docs.payments.sardine.ai/api_reference/onramp/payment-method/get-payment-method-information /api_reference/onramp.yaml get /payment-methods Get information about User's payment methods # Get Quote Source: https://docs.payments.sardine.ai/api_reference/onramp/quote/get-quote /api_reference/onramp.yaml get /quotes Sardine returns a quote on the amount of cryptocurrency that can be purchased or sold (for off-ramp), along with the associated fees, which are as follows - Network fee - Also known as "gas", paid out to faciliate and validate the transaction - Processing fee: Used to cover Sardine's cost of money movement, fraud check and compliance # Create Support Ticket Source: https://docs.payments.sardine.ai/api_reference/onramp/support/create-support-ticket /api_reference/onramp.yaml post /supportTickets This endpoint allows users to file a support ticket with Sardine by providing their contact information and details about the issue. # Get Client Token Source: https://docs.payments.sardine.ai/api_reference/onramp/user-onboarding/get-client-token /api_reference/onramp.yaml post /auth/client-tokens Exchange your `clientId` and `clientSecret` for a `clientToken` that can be be used in frontend code. `clientToken` will be unusable after the `expiresAt` time, which will normally be after 30 min. To try the request in the mock server on the right, substitute username for clientId and password for clientSecret. If `reference_id` is passed, it will be passed to the Order object upon when the transaction happens. It can then be used as a filter in the /orders endpoint # Get Customers Source: https://docs.payments.sardine.ai/api_reference/onramp/user-onboarding/get-customers /api_reference/onramp.yaml get /customers Fetches list of all customers. Can be filtered by passing `customerId` # Get KYC Widget URL Source: https://docs.payments.sardine.ai/api_reference/onramp/user-onboarding/get-kyc-widget-url /api_reference/onramp.yaml get /kyc/widgetUrl This endpoint returns a URL that redirects the user to perform document-based KYC verification. # Post Customer Information Source: https://docs.payments.sardine.ai/api_reference/onramp/user-onboarding/post-customer-information /api_reference/onramp.yaml post /customers Send User information to Sardine to store theie information and create a risk profile # Supported Assets Source: https://docs.payments.sardine.ai/coverage/supported_assets Sardine supports a focused set of digital assets for on-ramp and off-ramp flows, routed through our liquidity provider. Our current asset coverage is scoped to the tokens supported by our active liquidity provider. Assets marked as **Yes** under *Instant Settlement* can be funded or settled in near real time, reducing risk and improving user experience. The list below reflects our current default coverage. The definitive, up-to-date list for your account is always the response from [`GET /v1/supported-tokens`](/api_reference), since availability can vary by account configuration and liquidity provider routing. ### | Token | Networks | Instant Settlement | | ----- | ------------------ | ------------------ | | BTC | Bitcoin | Yes | | ETH | Ethereum | Yes | | USDC | Ethereum, Arbitrum | Yes | | USDT | Ethereum, Tron | Yes | ### Key Highlights * **Stablecoin coverage:** USDC (Ethereum, Arbitrum) and USDT (Ethereum, Tron) are supported with instant settlement. * **Bitcoin and Ethereum:** Core assets Bitcoin and Ethereum are available for both on- and off-ramps. * **Reduced coverage from prior provider:** We recently consolidated onto a single liquidity provider, which narrowed asset coverage compared to previous versions of this page. If you relied on a token no longer listed here, reach out to your Sardine contact. * **Scalable coverage:** Sardine continuously evaluates and adds assets based on demand and compliance requirements. # Geographic Coverage Source: https://docs.payments.sardine.ai/coverage/supported_geos On-ramp and off-ramp coverage across 80+ countries, with compliance and fraud protections built in. Sardine provides global reach for payments, supporting both consumer and enterprise flows. Our coverage spans North America, Latin America, Europe, Africa, and Asia. We support local regulatory requirements in each market, ensuring secure and compliant transactions. Partners can enable: * **On-Ramp:** Allow users to buy crypto or fund stablecoin wallets with local payment methods. * **Off-Ramp:** Let users or businesses cash out to bank accounts or cards in local currencies. * **NFT Checkout:** Direct purchase of NFTs with cards or bank accounts where supported ### Supported Markets | Country | Country Code | On-Ramp | Off-Ramp | NFT Checkout | | ---------------------------- | ------------ | --------------------- | --------------------- | --------------------- | | United States (Excl. NY, AK) | US | | | | | United States (NY, AK) | US | | | | | Albania | AL | | | | | Angola | AO | | | | | Austria | AT | | | | | Barbados | BB | | | | | Belgium | BE | | | | | Belize | BZ | | | | | Benin | BJ | | | | | Bolivia | BO | | | | | Brazil | BR | | | | | Bulgaria | BG | | | | | Cambodia | KH | | | | | Cayman Islands | KY | | | | | Chile | CL | | | | | Colombia | CO | | | | | Comoros | KM | | | | | Costa Rica | CR | | | | | Croatia | HR | | | | | Cyprus | CY | | | | | Czechia | CZ | | | | | Denmark | DK | | | | | Dominica | DM | | | | | Dominican Republic | DO | | | | | Ecuador | EC | | | | | Egypt | EG | | | | | El Salvador | SV | | | | | Equatorial Guinea | GQ | | | | | Estonia | EE | | | | | Faroe Islands | FO | | | | | Finland | FI | | | | | France | FR | | | | | French Guiana | GF | | | | | Germany | DE | | | | | Greece | GR | | | | | Guinea | GN | | | | | Guinea-Bissau | GW | | | | | Guyana | GY | | | | | Haiti | HT | | | | | Honduras | HN | | | | | Hungary | HU | | | | | Iceland | IS | | | | | Indonesia | ID | | | | | Ireland | IE | | | | | Israel | IL | | | | | Italy | IT | | | | | Jamaica | JM | | | | | Japan | JP | | | | | Kyrgyzstan | KG | | | | | Laos | LA | | | | | Latvia | LV | | | | | Liechtenstein | LI | | | | | Lithuania | LT | | | | | Luxembourg | LU | | | | | Madagascar | MG | | | | | Malaysia | MY | | | | | Maldives | MV | | | | | Malta | MT | | | | | Mauritania | MR | | | | | Mexico | MX | | | | | Mongolia | MN | | | | | Mozambique | MZ | | | | | Netherlands | NL | | | | | Norway | NO | | | | | Oman | OM | | | | | Panama | PA | | | | | Paraguay | PY | | | | | Peru | PE | | | | | Philippines | PH | | | | | Poland | PL | | | | | Portugal | PT | | | | | Romania | RO | | | | | Saint Kitts and Nevis | KN | | | | | Saint Martin | MF | | | | | Saudi Arabia | SA | | | | | Seychelles | SC | | | | | Singapore | SG | | | | | Slovakia | SK | | | | | Slovenia | SI | | | | | South Korea | KR | | | | | Spain | ES | | | | | Sri Lanka | LK | | | | | Sweden | SE | | | | | Switzerland | CH | | | | | Tanzania | TZ | | | | | Thailand | TH | | | | | Trinidad and Tobago | TT | | | | | Turkey | TR | | | | | United Arab Emirates | AE | | | | | United Kingdom | GB | | | | | Uruguay | UY | | | | | Uzbekistan | UZ | | | | | Vanuatu | VU | | | | | Vietnam | VN | | | | ### Key Highlights * **United States coverage:** Available in all states, with specific restrictions in New York and Alaska. * **Europe:** Broad SEPA coverage for both on- and off-ramps. * **Emerging markets:** Expanding presence in Latin America, Africa, and Asia to support global crypto and stablecoin adoption. * **Scalable roadmap:** Sardine continuously evaluates and adds new countries based on partner demand and regulatory clearance. # Payment Methods Source: https://docs.payments.sardine.ai/coverage/supported_payment_methods Global coverage across cards, bank transfers, and wallets, all optimized with Sardine’s risk and compliance platform. Sardine supports a wide range of payment methods so you can meet users wherever they are. You can enable all options or configure only the ones that make sense for your business. Our platform manages fraud, compliance, and authorization for every transaction. The result is higher approval rates, lower fraud, and less friction for your users. ### Support | Payment Method | Region | On-Ramp | Off-Ramp | | --------------------------- | ------ | --------------------- | --------------------- | | Instant ACH / Bank Transfer | US | | | | Credit / Debit Card | Global | | | | Apple Pay | Global | | | | Google Pay | Global | | | | SEPA | EU | ✓ | | ### Instant ACH and Bank Transfer Users in the United States can link a bank account and fund transactions instantly with Instant ACH, or use a standard ACH transfer that settles in two to three business days. All connections are made securely through trusted bank-linking providers. Bank transfers are a cost-effective funding method and give users confidence by keeping full control of their accounts. ### Credit and Debit Cards Global card network support allows users to fund transactions quickly and securely. Sardine operates as the Merchant of Record, managing authorization, fraud checks, and disputes. This reduces false declines and improves acceptance rates. Fees vary by market and card type. ### Apple Pay and Google Pay Users can complete purchases instantly using Apple Pay or Google Pay. These wallet options remove the need to re-enter payment details, create a smoother mobile experience, and increase conversion at checkout. ### SEPA Bank Transfer For users in the European Union, SEPA transfers provide a reliable way to fund accounts or withdraw directly to their bank. Sardine supports both on-ramp and off-ramp SEPA flows with built-in KYC and fraud protection. # API Integration Source: https://docs.payments.sardine.ai/integration_guides/identity/api_integration Full implementation reference for the Sardine Universal Identity API ## Authentication All Identity API endpoints use HTTP Basic Auth. Pass your `clientId` as the username and `clientSecret` as the password on every request. ```bash theme={null} curl https://api.sandbox.sardine.ai/v1/identity/... \ -u "$CLIENT_ID:$CLIENT_SECRET" ``` Never make these calls from a browser or mobile client. Your `clientSecret` must remain server-side only. *** ## Step 1 — Check if the customer exists Before creating a new customer, check whether one already exists for the user's phone number to avoid duplicate records. ```bash theme={null} curl -X POST https://api.sandbox.sardine.ai/v1/identity/entities/search \ -u "$CLIENT_ID:$CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "phoneNumber": "+14155551234" }' ``` If `customerId` is returned, the customer already exists — skip to [Step 3](#step-3--generate-a-widget-url). If the response is empty, proceed to Step 2. *** ## Step 2 — Create the customer Register the user with their phone number. The `customerId` returned here is your durable reference to this user in all subsequent API calls. ```bash theme={null} curl -X POST https://api.sandbox.sardine.ai/v1/identity/entities \ -u "$CLIENT_ID:$CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "phoneNumber": "+14155551234" }' ``` ```json theme={null} { "customerId": "3f8c1a22-1234-4abc-9def-000000000001", "createdAt": "2026-06-01T10:00:00Z" } ``` Store `customerId` against your user record in your own database. *** ## Step 3 — Generate a widget URL Call this endpoint from your backend to get a hosted widget URL for the user. Choose the right `flow` and `scope` for your use case. ```bash theme={null} curl -X POST https://api.sandbox.sardine.ai/v1/identity/consents/widget \ -u "$CLIENT_ID:$CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "customerId": "3f8c1a22-1234-4abc-9def-000000000001", "successUrl": "https://yourapp.com/kyc/success", "manualKycUrl": "https://yourapp.com/kyc/manual", "scope": ["profile", "doc_kyc"], "flow": "kyc_input" }' ``` ```json theme={null} { "widgetUrl": "https://identity.sardine.ai/?client_token=abc123&consent_id=xyz789&success_url=..." } ``` ### Choosing a flow | Flow | When to use | | ------------- | ---------------------------------------------------------------------------------------------------------------------- | | `kyc_input` | New users, or when you need the user to verify additional scopes not yet on file | | `kyc_sharing` | User has already been verified by another Sardine partner and you want them to consent to share that identity with you | ### Choosing scopes | Scope | What it collects | | ---------- | -------------------------------------------------------------- | | `profile` | Name, date of birth, address, email, phone number | | `doc_kyc` | Government ID scan (front + back) and biometric liveness check | | `liveness` | Liveness check only | | `ssn` | Social Security Number (US users, when required) | Pass multiple scopes together: `["profile", "doc_kyc"]` is the standard full-KYC combination. ### manualKycUrl Provide a `manualKycUrl` as a fallback destination if the user cannot be verified automatically (e.g. document scan quality is too low). This is optional but recommended for production. *** ## Step 4 — Redirect the user Return the `widgetUrl` to your frontend and redirect the user to it, or embed it in an iframe. ```js theme={null} // Server response to your frontend res.json({ widgetUrl: data.widgetUrl }); // Frontend redirect window.location.href = widgetUrl; ``` The widget handles all verification steps. When the user completes (or abandons) the flow, they are redirected to your `successUrl`. *** ## Step 5 — Retrieve the verified identity After the user returns to your `successUrl`, call this endpoint from your backend to retrieve the verified data. ```bash theme={null} curl https://api.sandbox.sardine.ai/v1/identity/entities/3f8c1a22-1234-4abc-9def-000000000001 \ -u "$CLIENT_ID:$CLIENT_SECRET" ``` ### Response ```json theme={null} { "profile": { "userId": "3f8c1a22-1234-4abc-9def-000000000001", "clientId": "your-client-id", "consentId": "b1c2d3e4-5678-4abc-9def-000000000002", "consentedAt": "2026-06-01T10:30:00Z", "revokedAt": null, "primaryIdentity": true, "fullName": "Jane Smith", "dateOfBirth": "1990-06-15", "emailAddress": "jane@example.com", "phoneNumber": "+14155551234", "address": { "street": "123 Main St", "city": "San Francisco", "region": "CA", "postalCode": "94105" } }, "documentData": { "documentType": "DRIVERS_LICENSE", "documentNumber": "D1234567", "dateOfBirth": "1990-06-15", "expiryDate": "2028-06-15", "issuingCountry": "US", "firstName": "Jane", "lastName": "Smith" }, "documentKyc": { "front": "", "back": "", "selfie": "" } } ``` ### What's included per scope | Field | Requires scope | | ---------------------- | -------------- | | `profile` | `profile` | | `documentData` | `doc_kyc` | | `documentKyc` (images) | `doc_kyc` | Fields outside the consented scopes are returned as `null`. ### Consent states If the identity belongs to another client (i.e. `kyc_sharing` flow), the API enforces consent state: | State | Behaviour | | ------------------------------------------- | ------------------------------ | | Consent not found | `400 Consent not found` | | Consent pending (user has not approved yet) | `400 Pending user consent` | | Consent revoked | `400 Consent has been revoked` | | Consent active | `200` with full data | *** ## Error reference | Status | Message | Resolution | | ------ | ------------------------------------- | --------------------------------------------------------------------------------- | | `400` | `Phone number is required` | Include `phoneNumber` in the request body | | `400` | `Customer already exists` | Use the existing `customerId` from `/identity/entities/search` | | `400` | `Customer ID is required` | Include `customerId` in the widget request | | `400` | `Customer not found for customer ID` | Verify the `customerId` was created by this client | | `400` | `Invalid scope` | Use one of: `profile`, `doc_kyc`, `liveness`, `ssn` | | `400` | `User already consented to this flow` | The user has already completed `kyc_input` for this client | | `401` | Unauthorized | Check that `clientId` and `clientSecret` are correct and being sent as Basic Auth | *** ## Go to production 1. Test the full flow end-to-end in sandbox. 2. Confirm identity data is retrieved correctly after widget completion. 3. Contact your Sardine integration contact to complete the review. 4. Swap `api.sandbox.sardine.ai` → `api.sardine.ai` and replace with production credentials. # Overview Source: https://docs.payments.sardine.ai/integration_guides/identity/overview How the Sardine Universal Identity integration works end-to-end The Sardine Identity integration lets you collect and reuse verified user identities through a hosted widget backed by a simple server-side API. Your backend holds the credentials; your frontend never touches them. There are two flows: * **`kyc_input`** — A new user verifies their identity for the first time. The widget collects personal information, captures a government ID, and runs a liveness check. * **`kyc_sharing`** — A returning Sardine network user has already been verified by another partner. They consent to share their existing verified identity with you. This takes seconds. Both flows produce the same result: a verified identity you can retrieve via `GET /identity/entities/{customerId}`. ## Architecture ```mermaid theme={null} sequenceDiagram actor U as User participant C as Your Backend participant S as api.sardine.ai participant W as identity.sardine.ai note over C,S: Server-side setup C->>S: POST /identity/entities (phoneNumber) S-->>C: { customerId } note over C,W: Generate widget URL C->>S: POST /identity/consents/widget (customerId, scope, flow) S-->>C: { widgetUrl } C-->>U: Redirect user to widgetUrl note over U,W: User completes verification U->>W: Verifies identity (ID scan, liveness, etc.) W-->>U: Redirects to successUrl note over C,S: Retrieve verified data C->>S: GET /identity/entities/{customerId} S-->>C: { profile, documentData, documentKyc } ``` ## Key Concepts **customerId** — A Sardine-assigned UUID created when you register a user via `POST /identity/entities`. Store this against your own user record; you'll use it for all subsequent API calls. **scope** — Controls which data the widget collects or shares. Common combinations: * `["profile"]` — Personal info only (name, DOB, address, email, phone) * `["profile", "doc_kyc"]` — Full KYC with government ID and liveness check * `["doc_kyc"]` — Document scan only (for users whose basic profile is already on file) **flow** — `kyc_input` for new verifications, `kyc_sharing` for reusing an existing verified identity from the Sardine network. **widgetUrl** — A one-time URL generated server-side. Redirect the user to this URL or embed it in an iframe. The URL encodes a session token and consent ID — it does not need to be kept secret but should be used promptly. ## Next Steps * [Quickstart](/integration_guides/identity/quickstart) — Go live in four steps * [API Integration](/integration_guides/identity/api_integration) — Full implementation reference # Quickstart Source: https://docs.payments.sardine.ai/integration_guides/identity/quickstart Get Sardine Universal Identity running in four steps ## 1. Get your credentials Contact your Sardine integration contact to receive a `clientId` and `clientSecret` for the sandbox environment. All API calls use HTTP Basic Auth with these credentials. Never expose your `clientSecret` in frontend code. All calls to `api.sardine.ai` must be made from your backend. ## 2. Create a customer Register the user in the Sardine system using their phone number. Store the returned `customerId` against your own user record. ```bash theme={null} curl -X POST https://api.sandbox.sardine.ai/v1/identity/entities \ -u "$CLIENT_ID:$CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "phoneNumber": "+14155551234" }' ``` ```json theme={null} { "customerId": "3f8c1a22-1234-4abc-9def-000000000001", "createdAt": "2026-05-01T10:00:00Z" } ``` ## 3. Generate a widget URL and redirect the user Request a widget URL from your backend, then redirect the user to it. The widget handles all verification steps. ```bash theme={null} curl -X POST https://api.sandbox.sardine.ai/v1/identity/consents/widget \ -u "$CLIENT_ID:$CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "customerId": "3f8c1a22-1234-4abc-9def-000000000001", "successUrl": "https://yourapp.com/kyc/success", "scope": ["profile", "doc_kyc"], "flow": "kyc_input" }' ``` ```json theme={null} { "widgetUrl": "https://identity.sardine.ai/?client_token=abc123&consent_id=xyz789&success_url=..." } ``` Redirect the user to the `widgetUrl`. When they finish, Sardine redirects them back to your `successUrl`. ## 4. Retrieve the verified identity Once the user returns to your `successUrl`, fetch their verified data from your backend. ```bash theme={null} curl https://api.sandbox.sardine.ai/v1/identity/entities/3f8c1a22-1234-4abc-9def-000000000001 \ -u "$CLIENT_ID:$CLIENT_SECRET" ``` ```json theme={null} { "profile": { "userId": "3f8c1a22-1234-4abc-9def-000000000001", "fullName": "Jane Smith", "dateOfBirth": "1990-06-15", "emailAddress": "jane@example.com", "phoneNumber": "+14155551234", "address": { "street": "123 Main St", "city": "San Francisco", "region": "CA", "postalCode": "94105" } }, "documentData": { "documentType": "DRIVERS_LICENSE", "documentNumber": "D1234567", "issuingCountry": "US" }, "documentKyc": { "front": "", "back": "", "selfie": "" } } ``` *** Once you've completed a successful end-to-end test in sandbox, reach out to your Sardine contact to complete the integration review and receive production credentials. For a full implementation reference see the [API Integration guide](/integration_guides/identity/api_integration). # NFT Checkout with Crypto Payout Source: https://docs.payments.sardine.ai/integration_guides/nft_checkout/nft_checkout_payout Sardine's NFT checkout widget offers a quick way to integrate the ability to directly purchase NFTs from fiat through a URL, and then settle with crypto. This is best suited for quick integrations where the developer does not want to build their own UI. The Sardine Risk SDK is natively integrated into the checkout form. [Example URL](https://crypto.sandbox.sardine.ai/?client_token=123-absc-1231\&show_features=true) **Goal** By the end of this guide, you should be able to open a new window with Sardine NFT Checkout, either in a new tab or in a new browser window, and receive payout to a wallet of your choice. ## Implementing NFT Checkout Before we start, you'll need the following parameters ```json jsonSchema theme={null} { "title": "Authorization Parameters", "type": "object", "properties": { "clientId": { "type": "string", "description": "A unique Client Identifier issued by Sardine for an integration. This is safe to be exposed to the public internet. This is needed for client side JS" }, "clientSecret": { "type": "number", "description": "The Secret Key is associated with a specific Client ID. It must be kept secret." }, }, "required": ["clientId", "clientSecret"] } ``` ### 1. Obtain authorization token The next step is to obtain the `clientToken`, which is a unique identifier for each session and user. Make a POST request to `/v1/auth/client-tokens` using Basic Auth by passing base64 encoding of `:` The body of this request is used to send information about the NFT and the user to Sardine. More information about this endpoint can be found [here](https://sardineai.stoplight.io/docs/integrate-payments/branches/main/9ed21dfe5c8ec-post-client-token) ```json jsonSchema theme={null} { "title": "clientToken Request", "type": "object", "properties": { "customerId": { "type": "string", "description": "ID of Customer that can be passed, in lieu of Sardine creating one" }, "referenceId": { "type": "string", "description": "Unique ID that should be passed to refer to this transaction. Status of this transaction will be fetched using this field as the key" }, "expiresIn" : { "type" : "string", "description" : "Time in seconds until the NFT will expire" }, "nft" : { "type" : "object", "description": "Metadata about NFT that needs to be passed", "properties": { "name": { "type" : "string", "description" : "Name of the NFT" }, "collection": { "type" : "string", "description" : "Collection the NFT belongs to" }, "price" : { "type" : "number", "description" : "Cost of the NFT in `currencyCode`" }, "currencyCode" : { "type" : "string", "description" : "Fiat currency payment happens in", "example" : "usd" }, "imageUrl" : { "type" : "string", "description" : "Url which is hosting the image of the NFT" }, }, "required" : ["name","price","currencyCode","imageUrl","expiration"] }, "taxRates": { "type": "object", "description": "Which contains rates for countries/regions in ISO3166-2 format.", "properties": { "US": { "type": "string", "description": "Countrycode like US. It's percentage, US: 10 means 10% tax for all US", "example": "US = 10" }, "US-NY": { "type": "string", "description": "countrycode-subdivisions like US-NY. \"US-NY\": 13 means 13% for NY state.", "example": "US-NY = 13" }, "US-CA": { "type": "string", "example": "US-CA = 20", "description": "countrycode-subdivisions like US-CA. \"US-CA\": 20 means 20% for CA state." } } }, "identityPrefill" : { "type" : "object", "description" : "User information that can be prefilled into the Checkout UI", "properties" : { "firstName" : { "type" : "string", "description" : "First name of buyer" }, "lastName" : { "type" : "string", "description" : "Last name of buyer" }, "dateOfBirth" : { "type" : "string", "description" : "Date of Birth of buyer in YYYY-MM-DD format" }, "emailAddress" : { "type" : "string", "description" : "Verified email address of buyer" }, "phone" : { "type" : "string", "description" : "Verified phone number of buyer" }, "address" : { "type" : "object", "properties" : { "street1" : { "type" : "string", "description" : "Street address" }, "street2" : { "type" : "string", "description" : "Suite, Apartment number etc" }, "city" : { "type" : "string", "description" : "City in address" }, "regionCode" : { "type" : "string", "description" : "2 letter state code" }, "postalCode" : { "type" : "string", "description" : "Zip code or equivalent" }, "countryCode" : { "type" : "string", "description" : "2 letter ISO country code" } } } } } }, "required": ["referenceId"] } ``` A sample request would look like below ```json http theme={null} { "method": "POST", "url": "https://api.sandbox.sardine.ai/v1/auth/client-tokens", "headers" : { "Authorization" : "Basic Y2xpZW50SWQ6Y2xpZW50U2VjcmV0", }, "body" : { "referenceId": "42eadcb0-4a93-45af-9c8c-d295db5aeb6c", "customerId": "adf02ae2-f633-11ec-b939-0242ac120002", "expiresIn" : 600, "nft": { "name": "NFT #1", "price": 100, "currencyCode": "USD", "contractAddress": "0x7fC0344254E1663C2eF24e3c063cbec231525C20", "imageUrl": "https://gateway.nftcompany.io/ipfsQmSAQm4gbhjSeUk7fuYppHd7Z8dfWpBvnFmqFSKqkrUJPM", "network" : "ethereum" }, "identityPrefill": { "firstName": "John", "lastName": "Doe", "dateOfBirth": "2000-01-01", "emailAddress": "foobar@gmail.com", "phone": "+19254485826", "address": { "street1": "123 Main st", "street2": "", "city": "irvine", "regionCode": "CA", "postalCode": "02747", "countryCode": "US" } } } } ```
If the request is successful, you should receive a response that contains the `clientToken`, which is needed to create the Checkout Use your base64 encode( clientId:clientSecret ) to make a call **Constraints** * referenceId - unique * expiresIn - 300 to 3600 ( 5min - 1hr) **Success Response:** ```json theme={null} { "clientToken": "", "expiresAt": "2022-07-07T21:32:29Z" } ``` **Error Response:** ```json theme={null} { "message": "Duplicate referenceId", "code": "INVALID_PARAMS" } ``` [A fully complete URL will look like this:](https://crypto.sandbox.sardine.ai/?client_token=\\&show_features=true>) ### 2. User goes through Sardine Checkout Once the Checkout URL is opened, the Sardine flow takes over and guides the user through the Checkout ### 3. Embed NFT checkout Once the checkout URL has been generated, it can be embedded into your web app as an iframe, with event handlers to catch events sent by the iframe. Sample code to embed NFT checkout Recommended size is width=500, height=700 for new window ```html theme={null}