{"openapi":"3.0.0","info":{"title":"GnosisPay API","version":"1.0.0","description":"OpenAPI documentation for GnosisPay"},"tags":[{"name":"Account Management","description":"Information about your Account"},{"name":"Authentication","description":"Authenticate to our API using SIWE"},{"name":"Card Management","description":"Manage all your Cards"},{"name":"IBAN","description":"Integrate with Monerium to issue IBANs"},{"name":"KYC","description":"KYC using Sumsub SDK"},{"name":"Physical Card Order","description":"Order a Physical Card and manage the process"},{"name":"Rewards","description":"Cashback Rewards"},{"name":"Safe Management","description":"Manage your Safe"},{"name":"Transactions","description":"Manage Card Transactions"},{"name":"User","description":"Manage User Information"},{"name":"Webhooks","description":"Manage Webhooks"}],"servers":[{"url":"https://api.gnosispay.com"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"AuthRequest":{"type":"object","properties":{"auth":{"type":"object","nullable":true,"$ref":"#/components/schemas/Authorization"}}},"Authorization":{"type":"object","required":["userId","iat","exp","hasSignedUp"],"properties":{"userId":{"type":"string"},"signerAddress":{"type":"string","nullable":true},"chainId":{"type":"string","nullable":true},"iat":{"type":"number"},"exp":{"type":"number"},"hasSignedUp":{"type":"boolean"}}},"Error":{"type":"object","properties":{"error":{"type":"string","description":"Error message","example":"Internal server error"}}},"Card":{"type":"object","required":["id","lastFourDigits"],"properties":{"id":{"type":"string"},"cardToken":{"type":"string"},"lastFourDigits":{"type":"string"},"activatedAt":{"type":"string","nullable":true,"format":"date-time"},"virtual":{"type":"boolean"}}},"CardOrder":{"type":"object","required":["id","createdAt","status","personalizationSource","totalDiscountEUR"],"properties":{"id":{"type":"string"},"transactionHash":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"status":{"type":"string","description":"Current order status in the state machine. See the state transition diagram in the documentation for valid transitions.","enum":["PENDINGTRANSACTION","TRANSACTIONCOMPLETE","CONFIRMATIONREQUIRED","READY","CARDCREATED","FAILEDTRANSACTION","CANCELLED"],"example":"PENDINGTRANSACTION"},"personalizationSource":{"type":"string","enum":["KYC","ENS"]},"embossedName":{"type":"string"},"address1":{"type":"string"},"address2":{"type":"string"},"city":{"type":"string"},"country":{"type":"string"},"postalCode":{"type":"string"},"state":{"type":"string"},"couponCode":{"type":"string"},"totalAmountEUR":{"type":"number","format":"double"},"totalDiscountEUR":{"type":"number","format":"double"},"virtual":{"type":"boolean"}}},"TermsBody":{"type":"object","required":["terms","version"],"properties":{"terms":{"type":"string","enum":["general-tos","card-monavate-tos","cashback-tos","privacy-policy"],"description":"Type of terms and conditions"},"version":{"type":"string","description":"Version of the terms document"}}},"CardAlreadyActiveError":{"type":"object","properties":{"error":{"type":"string","enum":["Card has been already activated"]}}},"CardBlockedError":{"type":"object","properties":{"error":{"type":"string","enum":["The card is blocked"]}}},"AssociatedSafeAccountNotFoundError":{"type":"object","properties":{"error":{"type":"string","enum":["Couldn't find an associated Safe account"]}}},"DelayTransaction":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the delayed transaction.","example":"clp3j1f9a0000a1cdh6ezx2qv"},"safeAddress":{"type":"string","description":"The Safe contract address associated with the transaction.","example":"0x1234567890abcdef1234567890abcdef12345678"},"transactionData":{"type":"string","description":"Data payload of the transaction.","example":"0xabcdef"},"enqueueTaskId":{"type":"string","description":"Identifier of the task that enqueued this transaction.","example":"task_abc123"},"dispatchTaskId":{"type":"string","nullable":true,"description":"Identifier of the task responsible for dispatching this transaction.","example":"task_def456"},"readyAt":{"type":"string","format":"date-time","nullable":true,"description":"Timestamp indicating when the transaction is ready for processing.","example":"2025-02-07T12:34:56Z"},"operationType":{"type":"string","enum":["CALL","DELEGATECALL"],"description":"Type of operation being performed.","example":"CALL"},"userId":{"type":"string","description":"Identifier of the user associated with the transaction.","example":"user_123"},"status":{"type":"string","enum":["QUEUING","WAITING","EXECUTING","EXECUTED","FAILED"],"description":"Current status of the transaction.","example":"QUEUING"},"createdAt":{"type":"string","format":"date-time","description":"Timestamp of when the transaction was created.","example":"2025-02-07T12:34:56Z"}}},"AccountAllowance":{"type":"object","properties":{"balance":{"type":"string","description":"The current balance of the account's allowance.","example":"1000000000000000000"},"refill":{"type":"string","description":"The refill amount for the account's allowance.","example":"2000000000000000000"},"period":{"type":"string","description":"The period for allowance refills.","example":"86400"},"nextRefill":{"type":"string","nullable":true,"description":"The timestamp for the next refill, if available.","example":"1633046400"}}},"AccountIntegrityStatus":{"type":"integer","description":"Enum representing the integrity status of the account","enum":[0,1,2,3,4,5,6,7,8],"x-enum-descriptions":["Ok (0): The account is in good standing with no issues","SafeNotDeployed (1): The Safe account has not been deployed yet","SafeMisconfigured (2): The Safe account has configuration issues","RolesNotDeployed (3): The Roles module has not been deployed","RolesMisconfigured (4): The Roles module has configuration issues","DelayNotDeployed (5): The Delay module has not been deployed","DelayMisconfigured (6): The Delay module has configuration issues","DelayQueueNotEmpty (7): The Delay queue contains pending transactions","UnexpectedError (8): An unexpected error occurred during validation"],"example":0},"SafeConfig":{"type":"object","properties":{"hasNoApprovals":{"type":"boolean","description":"Indicates whether the safe has no approvals.","example":false},"isDeployed":{"type":"boolean","description":"Indicates whether the safe is deployed.","example":true},"address":{"type":"string","nullable":true,"description":"The address of the safe, if available.","example":"0xabcdef1234567890abcdef1234567890abcdef12"},"tokenSymbol":{"type":"string","nullable":true,"description":"The token symbol associated with the safe.","example":"EURe"},"fiatSymbol":{"type":"string","nullable":true,"description":"The fiat symbol derived from the token symbol.","example":"EUR"},"accountStatus":{"$ref":"#/components/schemas/AccountIntegrityStatus","nullable":true,"description":"The integrity status of the account.\n\nPossible values:\n- **Ok (0)**: The account is in good standing with no issues\n- **SafeNotDeployed (1)**: The Safe account has not been deployed yet\n- **SafeMisconfigured (2)**: The Safe account has configuration issues\n- **RolesNotDeployed (3)**: The Roles module has not been deployed\n- **RolesMisconfigured (4)**: The Roles module has configuration issues\n- **DelayNotDeployed (5)**: The Delay module has not been deployed\n- **DelayMisconfigured (6)**: The Delay module has configuration issues\n- **DelayQueueNotEmpty (7)**: The Delay queue contains pending transactions\n- **UnexpectedError (8)**: An unexpected error occurred during validation\n"},"accountAllowance":{"$ref":"#/components/schemas/AccountAllowance","nullable":true,"description":"The allowance details for the account."}}},"SafeMigrationSafeInfo":{"type":"object","required":["address"],"properties":{"address":{"type":"string","example":"0xabcdef1234567890abcdef1234567890abcdef12"},"chainId":{"type":"string","nullable":true,"example":"100"},"tokenSymbol":{"type":"string","nullable":true,"example":"EURe"}}},"SafeMigrationOldSafeInfo":{"type":"object","required":["address","chainId","recordedAt"],"properties":{"address":{"type":"string","example":"0x1234567890abcdef1234567890abcdef12345678"},"chainId":{"type":"string","example":"100"},"recordedAt":{"type":"string","format":"date-time","example":"2026-06-03T12:00:00.000Z"}}},"SafeMigrationInfo":{"type":"object","required":["migrationId","hasOldSafe"],"properties":{"migrationId":{"type":"string","example":"safe-replacement-2026-06"},"status":{"type":"string","nullable":true,"enum":["PENDING","IN_PROGRESS","COMPLETED","FAILED"],"description":"Migration status, or null if the user has not started this migration."},"hasOldSafe":{"type":"boolean","description":"Whether a previous safe was recorded for this migration."},"newSafe":{"$ref":"#/components/schemas/SafeMigrationSafeInfo","nullable":true,"description":"The user's current active safe."},"oldSafe":{"$ref":"#/components/schemas/SafeMigrationOldSafeInfo","nullable":true,"description":"The previous safe recorded during migration, if any."}}},"KycQuestion":{"type":"object","properties":{"question":{"type":"string","description":"The text of the question."},"answers":{"type":"array","items":{"type":"string"},"description":"The possible answers to the question."}}},"KycAnswer":{"type":"object","properties":{"question":{"type":"string","description":"The text of the question being answered."},"answer":{"type":"string","description":"The user's answer to the question."}}},"Currency":{"type":"object","properties":{"symbol":{"type":"string"},"code":{"type":"string"},"decimals":{"type":"integer"},"name":{"type":"string"}}},"Country":{"type":"object","properties":{"name":{"type":"string"},"numeric":{"type":"string"},"alpha2":{"type":"string"},"alpha3":{"type":"string"}}},"Transaction":{"type":"object","properties":{"status":{"type":"string","enum":["Unsubmitted","Unconfirmed","ExecReverted","ExecSuccess"]},"to":{"type":"string"},"value":{"type":"string","description":"A BigInt value represented as a string"},"data":{"type":"string"},"hash":{"type":"string","nullable":true}}},"BasePaymentish":{"type":"object","properties":{"threadId":{"type":"string","description":"Thread ID for the transaction","example":"1234567890"},"createdAt":{"type":"string","format":"date-time"},"clearedAt":{"type":"string","format":"date-time","nullable":true,"description":"Date of the latest clearing record of the transaction"},"country":{"$ref":"#/components/schemas/Country"},"isPending":{"type":"boolean","description":"Whether the transaction is pending settlement.\n- For Payments: true when authorized but not yet cleared, false when settled\n- For Refunds: can be true if additional clearing steps are pending, typically false since they require both auth + clearing to appear\n- For Reversals: typically false as they're usually processed quickly\n"},"impactsCashback":{"type":"boolean","nullable":true,"description":"Indicates whether this transaction impacted cashback eligibility:\n- `true`: Transaction was eligible for and impacted cashback\n- `false`: Transaction did not impact cashback (not eligible)\n- `null`: Unable to determine (e.g., before user accepted cashback terms)\n"},"mcc":{"type":"string"},"merchant":{"type":"object","properties":{"name":{"type":"string"},"city":{"type":"string"},"country":{"$ref":"#/components/schemas/Country"}}},"billingAmount":{"type":"string","description":"A BigInt value represented as a string"},"billingCurrency":{"$ref":"#/components/schemas/Currency"},"transactionAmount":{"type":"string","description":"A BigInt value represented as a string"},"transactionCurrency":{"$ref":"#/components/schemas/Currency"},"transactionType":{"type":"string","description":"First 2 digits of the DE3 field (ISO 8583), representing the transaction type code.\nCommon values include (not limited to):\n- \"00\": Purchase (POS)\n- \"01\": Withdrawal (ATM)\n- \"10\": Account Funding\n- \"20\": Return of Goods\n- \"28\": Prepaid Load\n- \"30\": Balance Inquiry\n- \"70\": PIN Change\n- \"72\": PIN Unblock\n"},"cardToken":{"type":"string","description":"The token identifying the card used for this transaction"},"transactions":{"type":"array","items":{"$ref":"#/components/schemas/Transaction"}}}},"Payment":{"allOf":[{"$ref":"#/components/schemas/BasePaymentish"},{"type":"object","properties":{"kind":{"type":"string","enum":["Payment"]},"status":{"type":"string","enum":["Approved","IncorrectPin","InsufficientFunds","ExceedsApprovalAmountLimit","InvalidAmount","PinEntryTriesExceeded","IncorrectSecurityCode","Reversal","PartialReversal","Other"]}}}]},"Refund":{"allOf":[{"$ref":"#/components/schemas/BasePaymentish"},{"type":"object","properties":{"kind":{"type":"string","enum":["Refund"]},"refundAmount":{"type":"string","description":"A BigInt value represented as a string"},"refundCurrency":{"$ref":"#/components/schemas/Currency"}}}]},"Reversal":{"allOf":[{"$ref":"#/components/schemas/BasePaymentish"},{"type":"object","properties":{"kind":{"type":"string","enum":["Reversal"]},"reversalAmount":{"type":"string","description":"A BigInt value represented as a string"},"reversalCurrency":{"$ref":"#/components/schemas/Currency"}}}]},"Event":{"oneOf":[{"$ref":"#/components/schemas/Payment"},{"$ref":"#/components/schemas/Refund"},{"$ref":"#/components/schemas/Reversal"}]},"EOAAccount":{"type":"object","properties":{"id":{"type":"string","example":"clp3j1f9a0000a1cdh6ezx2qv"},"address":{"type":"string","example":"0x1234567890abcdef1234567890abcdef12345678"},"userId":{"type":"string","example":"user_123"},"createdAt":{"type":"string","format":"date-time","example":"2025-01-27T00:00:00Z"}}},"MoneriumIntegrationResponse":{"type":"object","properties":{"data":{"type":"object","required":["success","status","description"],"properties":{"success":{"type":"boolean","description":"Indicates whether the Monerium integration was successfully created","example":true},"status":{"type":"number","description":"HTTP status code of the operation","example":200},"description":{"type":"string","description":"Human-readable description of the operation result","example":"Successfully setup Monerium integration"},"responseData":{"type":"object","description":"Raw response data from Monerium API (only present on errors)","nullable":true},"moneriumProfileId":{"type":"string","description":"The Monerium profile ID assigned to the user (only present on success)","nullable":true,"example":"profile_123456789"},"iban":{"type":"string","description":"The assigned IBAN number (only present on success)","nullable":true,"example":"DE44500105175407324931"},"bic":{"type":"string","description":"The assigned BIC code (only present on success)","nullable":true,"example":"GENODEM1GLS"},"responseHeaders":{"type":"object","description":"Headers from the Monerium API response (only present on errors)","nullable":true,"example":{"content-type":"application/json"}}}}}},"IbanOrder":{"type":"object","required":["id","kind","currency","amount","address","counterpart","state","meta"],"properties":{"id":{"type":"string","description":"Unique identifier for the order."},"kind":{"type":"string","enum":["redeem","issue"],"description":"Type of order."},"currency":{"type":"string","enum":["eur","usd","gbp","isk"],"description":"Currency of the order."},"amount":{"type":"string","description":"Amount of the transaction in string format."},"address":{"type":"string","description":"Ethereum address associated with the order."},"counterpart":{"type":"object","required":["details","identifier"],"properties":{"details":{"type":"object","properties":{"name":{"type":"string"}}},"identifier":{"type":"object","oneOf":[{"properties":{"standard":{"type":"string","enum":["iban"]},"iban":{"type":"string"}},"required":["standard","iban"]},{"properties":{"standard":{"type":"string","enum":["chain"]},"address":{"type":"string"},"chain":{"type":"string"}},"required":["standard","address","chain"]}]}},"description":"Counterparty details."},"memo":{"type":"string","nullable":true,"description":"Optional memo for the order."},"state":{"type":"string","enum":["placed","pending","processed","rejected"],"description":"State of the order."},"meta":{"type":"object","required":["placedAt"],"properties":{"placedAt":{"type":"string","format":"date-time","description":"Timestamp when the order was placed."}}}}},"KYCStatus":{"type":"string","enum":["notStarted","documentsRequested","pending","processing","approved","resubmissionRequested","rejected","requiresAction"]},"SafeAccount":{"type":"object","required":["address","createdAt"],"properties":{"address":{"type":"string"},"chainId":{"type":"string"},"tokenSymbol":{"type":"string","example":"EURe"},"createdAt":{"type":"string","format":"date-time","example":"2025-01-27T00:00:00Z"}}},"BankingDetails":{"type":"object","properties":{"id":{"type":"string"},"address":{"type":"string"},"moneriumIban":{"type":"string"},"moneriumBic":{"type":"string"},"moneriumIbanStatus":{"type":"string"},"userId":{"type":"string"},"createdAt":{"type":"string","format":"date-time","example":"2025-01-27T00:00:00Z"},"updatedAt":{"type":"string","format":"date-time","example":"2025-01-27T00:00:00Z"}}},"User":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"firstName":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"address1":{"type":"string","nullable":true},"address2":{"type":"string","nullable":true},"city":{"type":"string","nullable":true},"postalCode":{"type":"string","nullable":true},"state":{"type":"string","nullable":true},"country":{"type":"string","nullable":true},"nationalityCountry":{"type":"string","nullable":true},"signInWallets":{"type":"array","items":{"$ref":"#/components/schemas/EOAAccount"}},"safeWallets":{"type":"array","items":{"$ref":"#/components/schemas/SafeAccount"}},"kycStatus":{"$ref":"#/components/schemas/KYCStatus"},"availableFeatures":{"type":"object","properties":{"moneriumIban":{"type":"boolean"}}},"cards":{"type":"array","items":{"$ref":"#/components/schemas/Card"}},"bankingDetails":{"type":"object","nullable":true,"$ref":"#/components/schemas/BankingDetails"},"isSourceOfFundsAnswered":{"type":"boolean"},"isPhoneValidated":{"type":"boolean"},"partnerId":{"type":"string","nullable":true},"status":{"type":"string","enum":["ACTIVE","DEACTIVATED"]}}}},"responses":{"InternalServerError":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"UnauthorizedError":{"description":"Unauthorized Error","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}},"paths":{"/api/v1/account-balances":{"get":{"summary":"Retrieve Account Balance","description":"Retrieves the balance information for the authenticated user (total, spendable and pending balances)","tags":["Account Management"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The account balance details.","content":{"application/json":{"schema":{"type":"object","required":["total","spendable","pending"],"properties":{"total":{"type":"string","format":"^[0-9]+$","description":"The total balance for this account (spendable and pending)."},"spendable":{"type":"string","format":"^[0-9]+$","description":"The amount that can be spent from this account."},"pending":{"type":"string","format":"^[0-9]+$","description":"The amount that is being reviewed for spending."}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/auth/nonce":{"get":{"tags":["Authentication"],"summary":"Generate nonce","responses":{"200":{"description":"Nonce generated successfully","content":{"text/plain":{"schema":{"type":"string","example":"a1b2c3d4e5f6"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/auth/challenge":{"post":{"tags":["Authentication"],"summary":"Verify SIWE signature","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["message","signature"],"properties":{"message":{"type":"string","description":"SIWE message containing the nonce"},"signature":{"type":"string","description":"EOA signature or EIP-1271 contract signature"},"ttlInSeconds":{"type":"number","description":"Represents the duration of the token in seconds. If not provided, defaults to 1 hour. Maximum 24 hours.","default":3600,"maximum":86400,"minimum":60}}}}}},"responses":{"200":{"description":"Signature verified successfully","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","description":"JWT token for API authentication"}}}}}},"401":{"description":"Invalid signature"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/auth/signup":{"post":{"summary":"Create a new User","description":"This endpoint creates a new `User` associating it with the provided email address.","tags":["Authentication"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["authEmail"],"properties":{"authEmail":{"type":"string","format":"email","description":"Email address for the new user"},"otp":{"type":"string","minLength":6,"maxLength":6,"description":"One-time password for email verification (optional during transition period)"},"marketingCampaign":{"type":"string","description":"Marketing campaign identifier"},"partnerId":{"type":"string","description":"Optional ID of the partner that referred the user"}}}}}},"responses":{"201":{"description":"User was created successfully","content":{"application/json":{"schema":{"type":"object","required":["id","token","hasSignedUp"],"properties":{"id":{"type":"string","description":"Unique identifier of the created user"},"token":{"type":"string","description":"JWT token for authentication"},"hasSignedUp":{"type":"boolean","description":"Indicates if the user has completed signup"}}}}}},"400":{"description":"Invalid partner ID","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Invalid partner ID"}}}}}},"401":{"description":"Invalid or expired OTP","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Invalid or expired OTP"}}}}}},"409":{"description":"Email address or wallet address already registered","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Email address already registered or Wallet address already associated with another account"}}}}}},"422":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Invalid email format"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Details about the server error","example":"An unexpected error occurred"}}}}}}}}},"/api/v1/auth/signup/otp":{"post":{"summary":"Request OTP for email verification","description":"This endpoint generates and sends a one-time password (OTP) to the provided email address for verification purposes.","tags":["Authentication"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","description":"Email address to send the OTP to"}}}}}},"responses":{"200":{"description":"OTP was sent successfully","content":{"application/json":{"schema":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean","description":"Indicates if the OTP was sent successfully","example":true}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"422":{"description":"Invalid request body","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Invalid email format"}}}}}},"500":{"description":"Failed to send OTP","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Failed to send OTP"}}}}}}}}},"/api/v1/cards/{cardId}/activate":{"post":{"summary":"Activate a Card","description":"## Prerequisites\n- Card must have not been activated\n- A Safe Account should be set for the authenticated user\n\nIf those conditions are met, the card is then activated.\nThe activated time will be the moment that this endpoint was triggered, in UTC.\n\n:::info\nThis action also notifies the user by email\n:::\n\n:::caution\n Be sure to have a Safe Account associated with the user. If a Safe Account is not tied to the user the endpoint will fail.\n\n To check if a user has a Safe Account, you can get the User details via `GET /api/v1/user` and check if there's at least one `safeWallets` tied to the user.\n\n A Safe Account can be created via `POST /api/v1/account`\n :::\n","tags":["Card Management"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"cardId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The card was activated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["Card activated successfully"]}}}}}},"400":{"description":"Missing signer address"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"No card found"},"422":{"description":"Request could not be processed","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/CardAlreadyActiveError"},{"$ref":"#/components/schemas/CardBlockedError"},{"$ref":"#/components/schemas/AssociatedSafeAccountNotFoundError"}]}}}},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/cards/{cardId}/freeze":{"post":{"summary":"Freeze a Card","description":"This will prevent the card from being used for any transactions.\n\n:::info\nThe card can be frozen and unfrozen instantly and multiple times.\n:::\n","tags":["Card Management"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"cardId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Card frozen successfully","content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["Card frozen successfully"]}}}}}},"400":{"description":"Invalid card status transition attempted"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"No card found"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/cards/{cardId}/lost":{"post":{"summary":"Report a Card as lost","tags":["Card Management"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"cardId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Card marked as lost successfully","content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["Card marked as lost successfully"]}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"No card found"},"409":{"description":"Card is already marked as lost","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","enum":["Card is already marked as lost"]}}}}}},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/cards/{cardId}/status":{"get":{"summary":"Get a Card status","tags":["Card Management"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"cardId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Card Status was retrieved successfully","content":{"application/json":{"schema":{"type":"object","required":["statusCode","isFrozen","isStolen","isLost","isBlocked","isVoid"],"properties":{"activatedAt":{"type":"string","format":"date-time"},"statusCode":{"type":"number"},"isFrozen":{"type":"boolean"},"isStolen":{"type":"boolean"},"isLost":{"type":"boolean"},"isBlocked":{"type":"boolean"},"isVoid":{"type":"boolean"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"No card found"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/cards/{cardId}/stolen":{"post":{"summary":"Report a Card as stolen","tags":["Card Management"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"cardId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Card marked as stolen successfully","content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["Card marked as stolen successfully"]}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"No card found"},"409":{"description":"Card is already marked as stolen","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","enum":["Card is already marked as stolen"]}}}}}},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/cards/{cardId}/unfreeze":{"post":{"summary":"Revert a Card freeze","description":"This will allow the card to be used for transactions. The card needs to be active and in a frozen state.\n\n:::info\nThe card can be frozen and unfrozen instantly and multiple times.\n:::\n","tags":["Card Management"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"cardId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Card unfrozen successfully","content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["Card unfrozen successfully"]}}}}}},"400":{"description":"Invalid card status transition attempted"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"No card found"},"422":{"description":"Card is not activated"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/cards/{cardId}/void":{"post":{"summary":"Void a Virtual Card","description":"Void a virtual card. Only virtual cards can be voided using this endpoint.","tags":["Card Management"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"cardId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Card marked as void successfully","content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["Card marked as void successfully"]}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"No card found"},"422":{"description":"Card cannot be voided / Card is already voided","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string","enum":["Only virtual cards can be voided","Card is already voided"]}}}}}},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/cards":{"get":{"summary":"List all Cards","tags":["Card Management"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"exclude_voided","schema":{"type":"boolean"},"description":"Exclude voided cards from the response"},{"in":"query","name":"status_code","schema":{"type":"string"},"description":"Filter cards by status code","example":"1000,1001"}],"responses":{"200":{"description":"The list of cards for a user","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["id","cardToken","lastFourDigits","activatedAt","virtual","statusCode","statusName"],"properties":{"id":{"type":"string"},"cardToken":{"type":"string"},"lastFourDigits":{"type":"string"},"activatedAt":{"type":"string","format":"date-time","nullable":true},"virtual":{"type":"boolean"},"statusCode":{"type":"number","description":"Card status code from payment processor. Possible values:\n- 1000: Active\n- 1001: Refer to Issuer\n- 1004: Capture\n- 1005: Declined\n- 1006: Pin Blocked\n- 1007: Declined\n- 1008: Honour with ID\n- 1009: Void\n- 1041: Lost\n- 1043: Stolen\n- 1054: Expired\n- 1154: Expired\n- 1062: Restricted\n- 1199: Void\n","enum":[1000,1001,1004,1005,1006,1007,1008,1009,1041,1043,1054,1154,1062,1199]},"statusName":{"type":"string","description":"Human-readable card status name corresponding to statusCode:\n- \"Active\": Card is active and can be used\n- \"Refer to Issuer\": Transaction requires issuer approval\n- \"Capture\": Card should be captured/retained\n- \"Declined\": All transactions are declined\n- \"Pin Blocked\": Card PIN is blocked due to incorrect attempts\n- \"Honour with ID\": Transaction requires ID verification\n- \"Void\": Card is voided/cancelled\n- \"Lost\": Card is reported as lost\n- \"Stolen\": Card is reported as stolen\n- \"Expired\": Card has expired\n- \"Restricted\": Card has restrictions applied\n- \"Unknown\": Status code not recognized\n"}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"No cards found"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/cards/virtual":{"post":{"summary":"Create a Virtual Card","tags":["Card Management"],"description":"Creates a virtual card without requiring a Card Order.\nVirtual cards are free and activated immediately.\nNo shipping address or payment validation is required.\n\n**Card Limits**: Users can have a maximum of 5 active cards (physical + virtual combined).\nActive cards exclude voided, lost, and stolen cards.\n","security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Virtual card created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"cardId":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"409":{"description":"User already has a card or card order in progress"},"422":{"description":"Unprocessable Entity - User validation failed. Possible reasons:\n- User has reached the maximum number of active cards (5)\n- User needs to complete KYC successfully\n- User's source of funds is not completed\n- User has incompatible risk score\n- User does not have a verified phone number\n- User's name is not set or contains invalid characters\n- User's address is not set\n- User's country is not supported\n- Could not create virtual card due to safe misconfiguration\n"},"500":{"description":"Internal server error"}}}},"/api/v1/cards/transactions":{"get":{"summary":"List Card Transactions","description":"Retrieves paginated transactions for all activated cards of the authenticated user.\n\nReturns three types of transaction events:\n- **Payment**: Regular card transactions (purchases, ATM withdrawals). Can appear immediately after authorization with `isPending: true`, then update when cleared.\n- **Refund**: Money returned to your account (product returns, cancellations). Only appears after both authorization and clearing are processed.\n- **Reversal**: Cancellation of previous transactions due to technical issues or merchant corrections. Can appear immediately after authorization-level reversals.\n\nThe final number might differ slightly, as one thread might contain multiple transactions.\n","tags":["Transactions"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"cardTokens","schema":{"type":"string"},"description":"Comma-separated list of card tokens"},{"in":"query","name":"limit","schema":{"type":"integer","default":100,"minimum":10},"description":"Maximum number of transactions to return"},{"in":"query","name":"offset","schema":{"type":"integer","default":0,"minimum":0},"description":"Number of transactions to skip"},{"in":"query","name":"before","schema":{"type":"string","format":"date-time"},"description":"Filter transactions before this date (ISO 8601 format, e.g., \"2023-04-01T00:00:00Z\")"},{"in":"query","name":"after","schema":{"type":"string","format":"date-time"},"description":"Filter transactions after this date (ISO 8601 format, e.g., \"2023-03-01T00:00:00Z\")"},{"in":"query","name":"billingCurrency","schema":{"type":"string"},"description":"Filter by billing currency code"},{"in":"query","name":"transactionCurrency","schema":{"type":"string"},"description":"Filter by transaction currency code"},{"in":"query","name":"mcc","schema":{"type":"string"},"description":"Filter by Merchant Category Code (MCC)"},{"in":"query","name":"transactionType","schema":{"type":"string"},"description":"Filter by transaction type code (e.g., \"00\" for Purchase, \"01\" for Withdrawal)"}],"responses":{"200":{"description":"Successful response with paginated transaction events","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer","description":"Total number of transactions available","example":25},"next":{"type":"string","nullable":true,"description":"URL for the next page of results, null if no more pages","example":"/api/v1/cards/transactions?limit=100&offset=100"},"previous":{"type":"string","nullable":true,"description":"URL for the previous page of results, null if on first page","example":null},"results":{"type":"array","description":"Array of transaction events for the current page","items":{"$ref":"#/components/schemas/Event"}}}},"examples":{"payment_pending":{"summary":"Payment (Pending)","description":"A pending card payment that hasn't been cleared yet","value":[{"createdAt":"2024-01-15T14:30:00Z","clearedAt":null,"isPending":true,"kind":"Payment","status":"Approved","country":{"name":"United Kingdom","numeric":"826","alpha2":"GB","alpha3":"GBR"},"mcc":"5411","merchant":{"name":"TESCO STORES","city":"LONDON","country":{"name":"United Kingdom","alpha2":"GB"}},"billingAmount":"2550","billingCurrency":{"symbol":"€","code":"EUR","decimals":2,"name":"Euro"},"transactionAmount":"2199","transactionCurrency":{"symbol":"£","code":"GBP","decimals":2,"name":"British Pound"},"transactionType":"00","cardToken":"4532********1234","transactions":[{"status":"ExecSuccess","to":"0x1234567890abcdef1234567890abcdef12345678","value":"2550000000000000000000","data":"0xa9059cbb","hash":"0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"}]}]},"payment_cleared":{"summary":"Payment (Cleared)","description":"A cleared card payment that has been settled","value":[{"createdAt":"2024-01-14T09:15:00Z","clearedAt":"2024-01-15T02:30:00Z","isPending":false,"kind":"Payment","status":"Approved","country":{"name":"Germany","numeric":"276","alpha2":"DE","alpha3":"DEU"},"mcc":"5814","merchant":{"name":"STARBUCKS","city":"BERLIN","country":{"name":"Germany","alpha2":"DE"}},"billingAmount":"450","billingCurrency":{"symbol":"€","code":"EUR","decimals":2,"name":"Euro"},"transactionAmount":"450","transactionCurrency":{"symbol":"€","code":"EUR","decimals":2,"name":"Euro"},"transactionType":"00","cardToken":"4532********1234","transactions":[{"status":"ExecSuccess","to":"0x1234567890abcdef1234567890abcdef12345678","value":"450000000000000000000","data":"0xa9059cbb","hash":"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"}]}]},"refund":{"summary":"Refund","description":"A refund transaction returning money to the account","value":[{"createdAt":"2024-01-13T16:45:00Z","clearedAt":"2024-01-14T08:20:00Z","isPending":false,"kind":"Refund","country":{"name":"France","numeric":"250","alpha2":"FR","alpha3":"FRA"},"mcc":"5651","merchant":{"name":"H&M PARIS","city":"PARIS","country":{"name":"France","alpha2":"FR"}},"billingAmount":"7500","billingCurrency":{"symbol":"€","code":"EUR","decimals":2,"name":"Euro"},"transactionAmount":"7500","transactionCurrency":{"symbol":"€","code":"EUR","decimals":2,"name":"Euro"},"transactionType":"20","cardToken":"4532********1234","refundAmount":"7500","refundCurrency":{"symbol":"€","code":"EUR","decimals":2,"name":"Euro"},"transactions":[{"status":"ExecSuccess","to":"0x1234567890abcdef1234567890abcdef12345678","value":"7500000000000000000000","data":"0xa9059cbb","hash":"0x9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba"}]}]},"reversal":{"summary":"Reversal","description":"A transaction reversal canceling a previous payment","value":[{"createdAt":"2024-01-12T11:20:00Z","clearedAt":"2024-01-12T11:25:00Z","isPending":false,"kind":"Reversal","country":{"name":"Netherlands","numeric":"528","alpha2":"NL","alpha3":"NLD"},"mcc":"5999","merchant":{"name":"ONLINE STORE","city":"AMSTERDAM","country":{"name":"Netherlands","alpha2":"NL"}},"billingAmount":"1200","billingCurrency":{"symbol":"€","code":"EUR","decimals":2,"name":"Euro"},"transactionAmount":"1200","transactionCurrency":{"symbol":"€","code":"EUR","decimals":2,"name":"Euro"},"transactionType":"00","cardToken":"4532********1234","reversalAmount":"1200","reversalCurrency":{"symbol":"€","code":"EUR","decimals":2,"name":"Euro"},"transactions":[{"status":"ExecSuccess","to":"0x1234567890abcdef1234567890abcdef12345678","value":"1200000000000000000000","data":"0xa9059cbb","hash":"0xfedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321"}]}]}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/cards/verify":{"post":{"summary":"Link physical card to user","description":"Verifies a card by decrypting PAN details and associating it with the authenticated user","deprecated":true,"tags":["Card Management"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["encryptedPan","encryptedKey","iv"],"properties":{"encryptedPan":{"type":"string","description":"Encrypted Primary Account Number","example":"encrypted_pan_value"},"encryptedKey":{"type":"string","description":"Encrypted key used for decryption","example":"encrypted_key_value"},"iv":{"type":"string","description":"Initialization vector for decryption","example":"iv_value"}}}}}},"responses":{"200":{"description":"Successfully verified and associated the card","content":{"application/json":{"schema":{"type":"object","required":["cardId"],"properties":{"cardId":{"type":"string","description":"The unique identifier of the verified card","example":"clp3j1f9a0000a1cdh6ezx2qv"}}}}}},"400":{"description":"Bad request - validation error or missing user data","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message","example":"Invalid request parameters"},"details":{"type":"object","description":"Detailed validation errors (optional)","nullable":true}}},"examples":{"invalid_parameters":{"summary":"Invalid request parameters","value":{"error":"Invalid request parameters","details":{"encryptedPan":{"_errors":["Required"]}}}},"no_user":{"summary":"No user found","value":{"error":"No user found"}},"no_country":{"summary":"User has no country set","value":{"error":"User has no country set"}},"missing_cardholder_details":{"summary":"User missing required cardholder details","value":{"error":"User missing required cardholder details","details":{"email":{"_errors":["Invalid email"]}}}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Unauthorized"}}}}}},"404":{"description":"Card not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Card not found"}}}}}},"422":{"description":"Card is in a state that prevents verification (e.g. void)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Card cannot be verified because it is void"}}}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the server error.","example":"An unexpected error occurred."}}}}}}}}},"/api/v1/delay-relay":{"get":{"summary":"List Delayed Transactions","description":"Returns an array of delayed transactions associated with the authenticated user, excluding failed transactions.","tags":["Safe Management"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"A list of delayed transactions for the authenticated user.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DelayTransaction"}}}}},"401":{"description":"Unauthorized, missing or invalid token."},"500":{"description":"Internal server error."}}}},"/api/v1/order/":{"get":{"tags":["Physical Card Order"],"summary":"List Physical Card Orders","description":"Retrieves all physical card orders for the authenticated user","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The card orders for the user","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["id","userId","status","personalizationSource","totalDiscountEUR","createdAt"],"properties":{"id":{"type":"string","format":"uuid","description":"The unique identifier of the card order.","example":"123e4567-e89b-12d3-a456-426614174000"},"transactionHash":{"type":"string","nullable":true,"description":"The on-chain transaction hash associated with the order.","example":"0x123abc..."},"embossedName":{"type":"string","nullable":true,"description":"The name embossed on the card.","example":"John Doe"},"address1":{"type":"string","nullable":true,"description":"The first line of the shipping address."},"address2":{"type":"string","nullable":true,"description":"The second line of the shipping address."},"city":{"type":"string","nullable":true,"description":"The city of the shipping address."},"postalCode":{"type":"string","nullable":true,"description":"The postal code of the shipping address."},"state":{"type":"string","nullable":true,"description":"The state of the shipping address."},"country":{"type":"string","nullable":true,"description":"The country of the shipping address."},"userId":{"type":"string","description":"The user id for this card order."},"status":{"type":"string","description":"Current order status","enum":["PENDINGTRANSACTION","TRANSACTIONCOMPLETE","CONFIRMATIONREQUIRED","READY","CARDCREATED","FAILEDTRANSACTION","CANCELLED"]},"personalizationSource":{"type":"string","enum":["KYC","ENS"]},"couponCode":{"type":"string","description":"The coupon code tied to this card order","example":"DISCOUNT2023"},"totalAmountEUR":{"type":"number","nullable":true,"example":20.99},"totalDiscountEUR":{"type":"number","example":1.99},"createdAt":{"type":"string","description":"When the order was created","format":"date-time","example":"2023-01-09T13:45:30Z"}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the server error.","example":"An unexpected error occurred."}}}}}}}}},"/api/v1/safe/config":{"get":{"summary":"Retrieve Safe Configuration","description":"Returns the configuration of the Safe account associated with the authenticated user, including deployment status, approvals, and account status and allowance details from the chain.","tags":["Safe Management"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successfully retrieved Safe configuration.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SafeConfig"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"description":"Internal server error."}}}},"/api/v1/safe/deploy":{"post":{"summary":"Deploy and Setup a Safe","description":"Deploys and sets up the Safe account for the authenticated user.\nThe User needs to be KYC approved.\n\nThis endpoint replaces the `POST /api/v1/account` and related endpoints.\nUsing this endpoint, the user can deploy the Safe without having to sign the data.\n\nThis endpoint is idempotent: calling it again while a deployment is\nalready in flight for the same user will return `202` without starting\na new workflow. Use `GET /api/v1/safe/deploy` as the source of truth\nfor deployment status (`processing`, `ok`, `failed`, `not_deployed`).\n","tags":["Safe Management"],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"dailyLimit":{"type":"integer","minimum":1,"description":"The daily spending allowance to configure for the Safe, in whole token units (no decimals). Defaults to 350 if omitted.","example":350}}}}}},"responses":{"202":{"description":"Accepted the deployment request. The partner should check the status of the deployment with the GET /api/v1/safe/deploy endpoint.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","description":"The status of the deployment.","example":"accepted"}}}}}},"400":{"description":"Bad request. The request body is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message"}}},"examples":{"invalidBody":{"value":{"error":"Invalid request body"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Forbidden. Missing signer address or Safe deployment is not available.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message"}}},"examples":{"missingSignerAddress":{"value":{"error":"Missing signer address"}},"safeDeploymentUnavailable":{"value":{"error":"Safe deployment is not available"}}}}}},"422":{"description":"Unprocessable Entity. Safe account already exists or user is not KYC approved.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message"}}},"examples":{"safeAccountAlreadyExists":{"value":{"error":"Safe account already exists"}},"kycRequired":{"value":{"error":"User is not KYC approved"}}}}}},"500":{"$ref":"#/components/responses/InternalServerError"}}},"get":{"summary":"Get the Safe deployment status.","description":"Returns the deployment status of the Safe account for the authenticated user.","tags":["Safe Management"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successfully retrieved the deployment status of the Safe account.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ok","not_deployed","processing","failed"],"description":"The status of the deployment.","example":"ok"},"updatedAt":{"type":"string","format":"date-time","description":"The timestamp of the last update.","example":"2021-01-01T00:00:00.000Z"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/safe/reset":{"delete":{"summary":"Reset Safe Account","description":"Permanently deletes the Safe account for the authenticated user. This operation is irreversible and should be used with caution.\n\n**Prerequisites for Safe Reset:**\n- Safe account must exist for the user\n- Safe account must not be in a properly configured state (AccountIntegrityStatus.Ok)\n- Safe account must not have transactions in the delay queue (AccountIntegrityStatus.DelayQueueNotEmpty)\n- User must not have any active (non-voided) cards linked to the Safe\n- Safe account must have zero token balance (all tokens must be withdrawn first)\n\n**Use Cases:**\n- Reset a Safe account that failed during deployment or setup\n- Clean up a Safe account that is in an inconsistent state\n- Remove a Safe account before creating a new one\n\n**Important Notes:**\n- This operation permanently deletes the Safe account record from the database\n- The actual Safe contract on-chain is not affected by this operation\n- Users will need to deploy a new Safe account after reset\n","tags":["Safe Management"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successfully reset the Safe account","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Success message confirming the Safe account was reset","example":"Safe account reset successfully"}}},"examples":{"success":{"summary":"Safe Reset Success","description":"The Safe account has been successfully reset and deleted","value":{"message":"Safe account reset successfully"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Safe account not found for the authenticated user","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Error message indicating no Safe account exists","example":"Safe account not found"}}},"examples":{"notFound":{"summary":"Safe Account Not Found","description":"No Safe account exists for the authenticated user","value":{"message":"Safe account not found"}}}}}},"422":{"description":"Safe account cannot be reset due to validation constraints","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Error message explaining why the Safe cannot be reset"}}},"examples":{"alreadySetup":{"summary":"Safe Already Properly Setup","description":"The Safe account is already in a properly configured state","value":{"message":"Safe account is already properly setup"}},"delayQueueNotEmpty":{"summary":"Delay Queue Not Empty","description":"The Safe account has pending transactions in the delay queue","value":{"message":"Safe account is already properly setup and has transactions in the delay queue"}},"hasActiveCards":{"summary":"Active Cards Linked","description":"The Safe account has active cards that must be voided first","value":{"message":"Safe account has cards linked to it, please void them first"}},"hasTokenBalance":{"summary":"Non-Zero Token Balance","description":"The Safe account has tokens that must be withdrawn first","value":{"message":"Safe account has tokens in it, please withdraw them first"}},"balanceCheckError":{"summary":"Balance Check Failed","description":"Unable to check the Safe account balance, please try again later","value":{"message":"Error fetching safe balance, please try again later"}}}}}},"500":{"description":"Internal server error occurred during the reset operation","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Generic error message for internal server errors","example":"Internal server error."}}},"examples":{"internalError":{"summary":"Internal Server Error","description":"An unexpected error occurred while processing the reset request","value":{"message":"Internal server error."}}}}}}}}},"/api/v1/safe/migration":{"get":{"summary":"Retrieve Safe migration status","description":"Returns the current safe, previous safe (if migrated), and migration status for the authenticated user.","tags":["Safe Management"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"migrationId","schema":{"type":"string","default":"safe-replacement-2026-06"},"description":"Migration identifier to look up."}],"responses":{"200":{"description":"Successfully retrieved safe migration info.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SafeMigrationInfo"}}}},"400":{"description":"Invalid query parameters."},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"description":"Internal server error."}}}},"/api/v1/safe/set-currency":{"post":{"summary":"Set Safe Currency","deprecated":true,"description":"This endpoint sets the appropriate token symbol (currency) for a user's Safe account based on their country.\nIt should be called after deploying a Safe account using the /api/v1/account endpoint.\n\nThe system assigns currencies based on user's country:\n- UK users (GB): GBPe\n- Brazil users (BR): USDCe\n- Users from other countries: EURe (default)\n\nPrerequisite: User must have completed and passed KYC verification.\n","tags":["Safe Management"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successfully set the currency for the Safe account","content":{"application/json":{"schema":{"type":"object","properties":{"tokenSymbol":{"type":"string","enum":["EURe","GBPe","USDCe"],"description":"The token symbol set for the Safe account"}}},"examples":{"success":{"value":{"tokenSymbol":"EURe"}}}}}},"400":{"description":"Bad request (e.g., no Safe account found for user)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message"}}},"examples":{"noSafe":{"value":{"error":"No Safe associated with user found in DB"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"422":{"description":"User needs to complete KYC successfully","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message"}}},"examples":{"kycRequired":{"value":{"error":"User needs to complete KYC successfully"}}}}}},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/source-of-funds":{"post":{"summary":"Answer Source of Funds questions","tags":["KYC"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/KycAnswer"}}}}},"responses":{"200":{"description":"Source of Funds answers submitted successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Source of funds submitted"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"$ref":"#/components/responses/InternalServerError"}}},"get":{"summary":"Retrieve Source of Funds questions","tags":["KYC"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"locale","schema":{"type":"string"},"description":"The locale for translating currency values (e.g., 'BR', 'UK')"}],"responses":{"200":{"description":"Successfully retrieved the Source of Funds questions.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/KycQuestion"}}}}},"401":{"description":"Unauthorized access.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message."}}}}}},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/transactions/{threadId}/dispute":{"post":{"summary":"Dispute a Transaction","description":"Create a ticket to dispute a transaction. The list of available dispute reason keys can be found in the `GET /api/v1/transactions/dispute` endpoint.\nIf the dispute reason is `unrecognized_transaction_report_fraudulent`, the user's card will be restricted.\n","tags":["Transactions"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"threadId","required":true,"schema":{"type":"string"},"description":"The thread ID of the transaction to dispute","example":"1234567890"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["disputeReason"],"properties":{"disputeReason":{"type":"string","enum":["purchase_cancelled_but_no_refund_received","problem_with_the_product_chargeback_","problem_with_service_subscription_chargeback","wrong_installment_number","wrong_value","charged_more_than_once","unrecognized_transaction_report_fraudulent"],"description":"The reason for disputing the transaction","example":"purchase_cancelled_but_no_refund_received"}}}}}},"responses":{"202":{"description":"Dispute submitted for review","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Dispute submitted for review"}}}}}},"400":{"description":"Bad request - Thread ID or dispute reason is required/invalid","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Valid dispute reason is required"},"validReasons":{"type":"array","items":{"type":"string"},"example":["purchase_cancelled_but_no_refund_received","problem_with_the_product_chargeback_"]}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Transaction not found or does not belong to user","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Transaction not found or does not belong to user"}}}}}},"409":{"description":"Transaction has already been disputed","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Transaction has already been disputed"},"message":{"type":"string","example":"This transaction has already been disputed and is being reviewed"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Internal server error"}}}}}}}}},"/api/v1/transactions/dispute":{"get":{"summary":"List Dispute Reasons","description":"Returns a list of available dispute reasons keys with their human-readable text. The keys need to be used in the dispute reason field when creating a dispute.","tags":["Transactions"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successfully retrieved dispute reasons","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"object","additionalProperties":{"type":"string"},"example":{"purchase_cancelled_but_no_refund_received":"Purchase Cancelled But No Refund Received","problem_with_the_product_chargeback_":"Problem With The Product (chargeback)","problem_with_service_subscription_chargeback":"Problem With Service/Subscription (chargeback)","wrong_installment_number":"Wrong Installment Number","wrong_value":"Wrong Value","charged_more_than_once":"Charged More Than Once","unrecognized_transaction_report_fraudulent":"Unrecognized Transaction - Report Fraudulent"}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/transactions":{"get":{"summary":"List Transactions (without pagination)","description":"This endpoint is deprecated. Please use [/api/v1/cards/transactions](#/Transactions/get_api_v1_cards_transactions) instead. Retrieves transactions for all activated cards of the authenticated user\n","deprecated":true,"tags":["Transactions"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"cardTokens","schema":{"type":"string"},"description":"Comma-separated list of card tokens"},{"in":"query","name":"before","schema":{"type":"string","format":"date-time"},"description":"Filter transactions before this date (ISO 8601 format, e.g., \"2023-04-01T00:00:00Z\")"},{"in":"query","name":"after","schema":{"type":"string","format":"date-time"},"description":"Filter transactions after this date (ISO 8601 format, e.g., \"2023-03-01T00:00:00Z\")"},{"in":"query","name":"billingCurrency","schema":{"type":"string"},"description":"Filter by billing currency code"},{"in":"query","name":"transactionCurrency","schema":{"type":"string"},"description":"Filter by transaction currency code"},{"in":"query","name":"mcc","schema":{"type":"string"},"description":"Filter by Merchant Category Code (MCC)"},{"in":"query","name":"transactionType","schema":{"type":"string"},"description":"Filter by transaction type code (e.g., \"00\" for Purchase, \"01\" for Withdrawal)"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Event"}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/verification/check":{"post":{"summary":"Verify a Phone Number (with OTP Code)","tags":["KYC"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}}}}},"responses":{"200":{"description":"Phone was verified successfully","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","example":true}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"422":{"description":"Validation error occurred.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["User has no phone number","Verification failed"]}}}}}},"500":{"description":"Failed to send verification."}}}},"/api/v1/verification":{"post":{"summary":"Retrieve an OTP code to verify a Phone Number","description":"This call replaces the existing phone number for a user if it exists, whether it's verified or not.","tags":["KYC"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["phoneNumber"],"properties":{"phoneNumber":{"type":"string","example":"+555599998888"}}}}}},"responses":{"200":{"description":"OTP was sent.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","example":true}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"User not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"User not found"}}}}}},"422":{"description":"Failed validation and OTP was not sent.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["Invalid phone number","Phone number already validated","User needs to be KYC approved"]}}}}}},"429":{"description":"Maximum verification attempts reached. Please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"500":{"description":"Failed to send verification."}}}},"/api/v1/accounts/daily-limit":{"get":{"summary":"Get current daily spending limit","description":"Retrieves the current daily spending limit for the authenticated user's Safe account.","tags":["Account Management"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successfully retrieved the current daily spending limit.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["dailyLimit","dailyRemaining"],"properties":{"dailyLimit":{"type":"integer","description":"The current daily spending limit in the Safe token's base units.","example":2500},"dailyRemaining":{"type":"integer","description":"The remaining daily spending limit in the Safe token's base units.","example":1000}}}}}}}},"401":{"description":"Unauthorized - invalid or missing authentication token."},"404":{"description":"Safe account or token not found for the user."},"500":{"description":"Internal server error."}}},"put":{"summary":"Set new daily spending limit","description":"Sets a new daily spending limit for the authenticated user's Safe account.\n\nThe signature should be generated by signing the EIP-712 typed data obtained from\nthe `/api/v1/accounts/daily-limit/transaction-data` endpoint.\nIf using a smart wallet, the smartWalletAddress is required for ERC1271 signatures.\n\nThe limit update is processed through a delay relay mechanism that executes after 3 minutes.\n\n**Note:** The newLimit must be an integer value between 1 and 8000.\n","tags":["Account Management"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["newLimit","signature","message"],"properties":{"newLimit":{"type":"integer","minimum":1,"maximum":8000,"description":"The new daily spending limit to set (must be an integer).","example":2500},"signature":{"type":"string","description":"The EIP-712 signature authorizing this limit change.","example":"0x1234567890abcdef..."},"message":{"type":"object","required":["salt","data"],"description":"The message object containing transaction data and salt from the EIP-712 typed data.","properties":{"salt":{"type":"string","description":"The salt value used in the EIP-712 typed data.","example":"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"},"data":{"type":"string","description":"The encoded transaction data from the typed data message.","example":"0xa8ec43eefe687fc128d1915040376d20ccb1bf40d838ddd82bf9b0ba3da683cc2a2516230000000000000000000000000000000000000000000000069d17119dc5a800000000000000000000000000000000000000000000000000069d17119dc5a800000000000000000000000000000000000000000000000000069d17119dc5a800000000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000000000006866fd60"}}},"smartWalletAddress":{"type":"string","description":"Optional. If using a smart account, the address of the smart wallet to use for the limit change.","example":"0x1234567890abcdef1234567890abcdef12345678"}}}}}},"responses":{"200":{"description":"Successfully submitted the daily limit update request.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","description":"The created delayed transaction details."}}}}}},"400":{"description":"Bad request - invalid signature."},"401":{"description":"Unauthorized - invalid or missing authentication token."},"404":{"description":"Safe account or token not found for the user."},"422":{"description":"Unprocessable Entity - validation errors in request body."},"500":{"description":"Internal server error."}}}},"/api/v1/accounts/daily-limit/transaction-data":{"get":{"summary":"Get EIP-712 typed data for setting daily limit","description":"Returns the EIP-712 typed data that needs to be signed by the user's wallet to set a new daily limit.\nThis endpoint is used as part of a three-step process:\n1. Call this endpoint to get the EIP-712 typed data\n2. Sign the typed data with the user's wallet using EIP-712 signature standard\n3. Submit the signature to the PUT `/api/v1/accounts/daily-limit` endpoint\n\n**Note:** The newLimit must be an integer value between 1 and 8000.\n","tags":["Account Management"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"newLimit","required":true,"description":"The new daily spending limit to set (1-8000, must be an integer).","schema":{"type":"string","pattern":"^[1-9][0-9]*$","minimum":1,"maximum":8000},"example":"2500"}],"responses":{"200":{"description":"Successfully retrieved EIP-712 typed data for signing.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["domain","primaryType","types","message"],"properties":{"domain":{"type":"object","required":["verifyingContract","chainId"],"properties":{"verifyingContract":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"The contract address that will verify the signature.","example":"0x3270bf32AB647e90eF94A026c70Aa1daaaDA2382"},"chainId":{"type":"number","description":"The chain ID for the network.","example":100}}},"primaryType":{"type":"string","enum":["ModuleTx"],"description":"The primary type for EIP-712 typed data signing.","example":"ModuleTx"},"types":{"type":"object","required":["ModuleTx"],"properties":{"ModuleTx":{"type":"array","description":"Array of type definitions for the ModuleTx structure.","items":{"type":"object","required":["type","name"],"properties":{"type":{"type":"string","description":"The field type.","example":"bytes"},"name":{"type":"string","description":"The field name.","example":"data"}}}}}},"message":{"type":"object","required":["data","salt"],"properties":{"data":{"type":"string","description":"The encoded transaction data for the daily limit change.","example":"0xa8ec43eefe687fc128d1915040376d20ccb1bf40d838ddd82bf9b0ba3da683cc2a2516230000000000000000000000000000000000000000000000069d17119dc5a800000000000000000000000000000000000000000000000000069d17119dc5a800000000000000000000000000000000000000000000000000069d17119dc5a800000000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000000000006866fd60"},"salt":{"type":"string","description":"The salt value for the typed data.","example":"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"}}}}}}}}}},"401":{"description":"Unauthorized - invalid or missing authentication token."},"404":{"description":"Safe account or token not found for the user."},"422":{"description":"Unprocessable Entity - validation errors in query parameters."},"500":{"description":"Internal server error."}}}},"/api/v1/accounts/onchain-daily-limit":{"get":{"summary":"Retrieve Onchain Daily Limit","description":"This endpoint is deprecated and will be removed in a future version.\nPlease use `GET /api/v1/accounts/daily-limit` instead.\n\nRetrieves the current onchain daily spending limit for the authenticated user's Safe account.\n","deprecated":true,"tags":["Account Management"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successfully retrieved the current onchain daily limit.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["onchainDailyLimit","onchainDailyRemaining"],"properties":{"onchainDailyLimit":{"type":"integer","description":"The current daily spending limit in the Safe token's base units.","example":2500},"onchainDailyRemaining":{"type":"integer","description":"The remaining daily spending limit in the Safe token's base units.","example":1000}}}}}}}},"401":{"description":"Unauthorized - invalid or missing authentication token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Authentication error message.","example":"Unauthorized"}}}}}},"404":{"description":"Safe account or token not found for the user.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message explaining why the request failed.","example":"Couldn't find associated Safe for the user"}}}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the server error.","example":"An unexpected error occurred."}}}}}}}},"put":{"summary":"Change Onchain Daily Limit with Signature","description":"This endpoint is deprecated and will be removed in a future version.\nPlease use `PUT /api/v1/accounts/daily-limit` instead.\n\nSets a new onchain daily spending limit for the authenticated user's Safe account.\nThis endpoint requires a valid signature from the user's wallet to authorize the change.\n\nThe signature should be generated by signing the transaction data obtained from\nthe `/api/v1/accounts/onchain-daily-limit/transaction-data` endpoint.\n\nThe limit update is processed through a delay relay mechanism that executes after 3 minutes.\n\n**Note:** The onchainDailyLimit must be an integer value between 1 and 8000.\n","deprecated":true,"tags":["Account Management"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["onchainDailyLimit","signature"],"properties":{"onchainDailyLimit":{"type":"integer","minimum":1,"maximum":8000,"description":"The new daily spending limit to set (must be an integer).","example":2500},"signature":{"type":"string","description":"The wallet signature authorizing this limit change.","example":"0x1234567890abcdef..."}}}}}},"responses":{"200":{"description":"Successfully submitted the daily limit update request.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["requestedOnchainDailyLimit"],"properties":{"requestedOnchainDailyLimit":{"type":"integer","description":"The daily limit value that was requested to be set.","example":2500}}}}}}}},"400":{"description":"Bad request - invalid signature.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Details about the validation error.","example":"Invalid signature provided"}}}}}},"401":{"description":"Unauthorized - invalid or missing authentication token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Authentication error message.","example":"Unauthorized"}}}}}},"404":{"description":"Safe account or token not found for the user.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message explaining why the request failed.","example":"Couldn't find associated Safe for the user"}}}}}},"422":{"description":"Unprocessable Entity - validation errors in request body.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Details about the validation error.","example":"signature is required"}}}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the server error.","example":"An unexpected error occurred."}}}}}}}}},"/api/v1/accounts/onchain-daily-limit/transaction-data":{"get":{"summary":"Retrieve Transaction Data for changing Daily Limit","description":"This endpoint is deprecated and will be removed in a future version.\nPlease use `GET /api/v1/accounts/daily-limit/transaction-data` instead.\n\nReturns the transaction data that needs to be signed by the user's wallet to set a new onchain daily limit.\nThis endpoint is used as part of a three-step process:\n1. Call this endpoint to get the transaction data\n2. Sign the transaction data with the user's wallet\n3. Submit the signature to the PUT `/api/v1/accounts/onchain-daily-limit` endpoint\n\n**Note:** The onchainDailyLimit must be an integer value between 1 and 8000.\n","deprecated":true,"tags":["Account Management"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"onchainDailyLimit","required":true,"description":"The new daily spending limit to set (1-8000, must be an integer).","schema":{"type":"string","pattern":"^[1-9][0-9]*$","minimum":1,"maximum":8000},"example":"2500"}],"responses":{"200":{"description":"Successfully retrieved transaction data for signing.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["transaction"],"properties":{"transaction":{"type":"object","required":["to","value","data"],"properties":{"to":{"type":"string","description":"The target contract address for the transaction.","example":"0x3270bf32AB647e90eF94A026c70Aa1daaaDA2382"},"value":{"type":"number","description":"The amount of native tokens to send with the transaction (usually 0).","example":0},"data":{"type":"string","description":"The encoded transaction data containing the function call.","example":"0xa8ec43eefe687fc128d1915040376d20ccb1bf40d838ddd82bf9b0ba3da683cc2a2516230000000000000000000000000000000000000000000000069d17119dc5a800000000000000000000000000000000000000000000000000069d17119dc5a800000000000000000000000000000000000000000000000000069d17119dc5a800000000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000000000006866fd60"}}}}}}}}}},"401":{"description":"Unauthorized - invalid or missing authentication token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Authentication error message.","example":"Unauthorized"}}}}}},"404":{"description":"Safe account or token not found for the user.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message explaining why the request failed.","example":"Couldn't find associated Safe for the user"}}}}}},"422":{"description":"Unprocessable Entity - validation errors in query parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Details about the validation error.","example":"onchainDailyLimit must be an integer"}}}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the server error.","example":"An unexpected error occurred."}}}}}}}}},"/api/v1/accounts/withdraw":{"post":{"summary":"Withdraw from Safe with Signature","description":"Withdraws ERC20 tokens or native tokens (xDAI) from the user's Safe account.\n\nFor ERC20 tokens, provide the token contract address.\nFor native token (xDAI) withdrawals, use \"0x0000000000000000000000000000000000000000\" as the tokenAddress.\n\nThe signature should be generated by signing the transaction data obtained from\nthe `/api/v1/accounts/withdraw/transaction-data` endpoint.\n\nThe withdrawal is processed through a delay relay mechanism that executes after 3 minutes.\n","tags":["Account Management"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["amount","to","tokenAddress","signature","message"],"properties":{"amount":{"type":"string","pattern":"^[1-9][0-9]*$","description":"The amount to withdraw in the token's base units.","example":"1000000000000000000"},"to":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"The address to withdraw to.","example":"0x3270bf32AB647e90eF94A026c70Aa1daaaDA2382"},"tokenAddress":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"The address of the token to withdraw. Use \"0x0000000000000000000000000000000000000000\" for native token (xDAI) withdrawals.","example":"0x3270bf32AB647e90eF94A026c70Aa1daaaDA2382"},"signature":{"type":"string","description":"The wallet signature authorizing this withdraw.","example":"0x1234567890abcdef..."},"message":{"type":"object","required":["salt","data"],"description":"The message object containing transaction data and salt.","properties":{"salt":{"type":"string","description":"The salt value used in the EIP-712 typed data.","example":"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"},"data":{"type":"string","description":"The encoded transaction data from the typed data message.","example":"0xa9059cbb0000000000000000000000003270bf32ab647e90ef94a026c70aa1daaaada23820000000000000000000000000000000000000000000000000de0b6b3a7640000"}}},"smartWalletAddress":{"type":"string","description":"Optional. If using a smart account, the address of the smart wallet to use for the withdraw.","example":"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"}}}}}},"responses":{"200":{"description":"Successfully submitted the withdraw request.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["id","safeAddress","transactionData","enqueueTaskId","operationType","userId","status","createdAt"],"properties":{"id":{"type":"string","description":"Unique identifier for the delayed transaction.","example":"clp3j1f9a0000a1cdh6ezx2qv"},"safeAddress":{"type":"string","description":"The Safe contract address associated with the transaction.","example":"0x1234567890abcdef1234567890abcdef12345678"},"transactionData":{"type":"string","description":"JSON stringified data payload of the transaction.","example":"{\"to\":\"0x123\",\"value\":\"0\",\"data\":\"0xabcdef\"}"},"enqueueTaskId":{"type":"string","description":"Identifier of the task that enqueued this transaction.","example":"task_abc123"},"dispatchTaskId":{"type":"string","nullable":true,"description":"Identifier of the task responsible for dispatching this transaction."},"readyAt":{"type":"string","format":"date-time","nullable":true,"description":"Timestamp indicating when the transaction is ready for processing."},"operationType":{"type":"string","enum":["CALL","DELEGATECALL"],"description":"Type of operation being performed.","example":"CALL"},"userId":{"type":"string","description":"Identifier of the user associated with the transaction.","example":"user_123"},"status":{"type":"string","enum":["QUEUING","WAITING","EXECUTING","EXECUTED","FAILED"],"description":"Current status of the transaction.","example":"QUEUING"},"createdAt":{"type":"string","format":"date-time","description":"Timestamp of when the transaction was created.","example":"2025-02-07T12:34:56Z"}}}}}}}},"401":{"description":"Unauthorized - invalid or missing authentication token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Authentication error message.","example":"Unauthorized"}}}}}},"404":{"description":"Safe account or token not found for the user.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message explaining why the request failed.","example":"Couldn't find associated Safe for the user"}}}}}},"422":{"description":"Unprocessable Entity - validation errors in request body.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Details about the validation error.","example":"amount must be a valid integer"}}}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the server error.","example":"An unexpected error occurred."}}}}}}}}},"/api/v1/accounts/withdraw/transaction-data":{"get":{"summary":"Retrieve Transaction Data for Withdrawing from Safe","description":"Returns the EIP-712 typed data that needs to be signed by the user's wallet to withdraw ERC20 tokens or native tokens (xDAI) from the user's Safe account.\n\nFor ERC20 tokens, provide the token contract address.\nFor native token (xDAI) withdrawals, use \"0x0000000000000000000000000000000000000000\" as the tokenAddress.\n\nThis endpoint is used as part of a three-step process:\n1. Call this endpoint to get the EIP-712 typed data\n2. Sign the typed data with the user's wallet using EIP-712 signature standard\n3. Submit the signature to the POST `/api/v1/accounts/withdraw` endpoint\n","tags":["Account Management"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"tokenAddress","required":true,"description":"The address of the token to withdraw. Use \"0x0000000000000000000000000000000000000000\" for native token (xDAI) withdrawals.","schema":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"},"example":"0x3270bf32AB647e90eF94A026c70Aa1daaaDA2382"},{"in":"query","name":"to","required":true,"description":"The address to withdraw to.","schema":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"},"example":"0x3270bf32AB647e90eF94A026c70Aa1daaaDA2382"},{"in":"query","name":"amount","required":true,"description":"The amount to withdraw in the token's base units.","schema":{"type":"string","pattern":"^[1-9][0-9]*$"},"example":"1000000000000000000"}],"responses":{"200":{"description":"Successfully retrieved EIP-712 typed data for signing.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["domain","primaryType","types","message"],"properties":{"domain":{"type":"object","required":["verifyingContract","chainId"],"properties":{"verifyingContract":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"The contract address that will verify the signature.","example":"0x3270bf32AB647e90eF94A026c70Aa1daaaDA2382"},"chainId":{"type":"number","description":"The chain ID for the network.","example":100}}},"primaryType":{"type":"string","enum":["ModuleTx"],"description":"The primary type for EIP-712 typed data signing.","example":"ModuleTx"},"types":{"type":"object","required":["ModuleTx"],"properties":{"ModuleTx":{"type":"array","description":"Array of type definitions for the ModuleTx structure.","items":{"type":"object","required":["type","name"],"properties":{"type":{"type":"string","description":"The field type.","example":"bytes"},"name":{"type":"string","description":"The field name.","example":"data"}}}}}},"message":{"type":"object","required":["data","salt"],"properties":{"data":{"type":"string","description":"The encoded transaction data for the withdrawal.","example":"0xa9059cbb0000000000000000000000003270bf32ab647e90ef94a026c70aa1daaaada23820000000000000000000000000000000000000000000000000de0b6b3a7640000"},"salt":{"type":"string","description":"The salt value for the typed data.","example":"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"}}}}}}}}}},"401":{"description":"Unauthorized - invalid or missing authentication token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Authentication error message.","example":"Unauthorized"}}}}}},"404":{"description":"Safe account or token not found for the user.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message explaining why the request failed.","example":"Couldn't find associated Safe for the user"}}}}}},"422":{"description":"Unprocessable Entity - validation errors in query parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Details about the validation error.","example":"amount must be a valid integer"}}}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the server error.","example":"An unexpected error occurred."}}}}}}}}},"/api/v1/cashback":{"get":{"summary":"Retrieve Cashback Information","description":"Returns user's OG status, GNO balance of Safe, cashback rate, and weekly spending cap.\nThe cashback rate is based on GNO balance tiers and includes the OG NFT holder bonus if applicable.\n\n**Note:** This cashback structure is valid from November 1st, 2025.\n","tags":["Cashback"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successfully retrieved cashback information","content":{"application/json":{"schema":{"type":"object","required":["isOg","gnoBalance","cashbackRate","weeklyCapUsd"],"properties":{"isOg":{"type":"boolean","description":"Indicates if the user holds an OG NFT token. If true, the user receives higher cashback rates.","example":true},"gnoBalance":{"type":"string","description":"User's GNO token balance in their Safe account (as string to preserve precision)","example":"10.5"},"cashbackRate":{"type":"number","description":"Cashback rate percentage (0-5%). Includes OG NFT bonus if applicable.","example":4},"weeklyCapUsd":{"type":"number","description":"Maximum weekly spending amount eligible for cashback in USD","example":500}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/eoa-accounts":{"get":{"summary":"List authenticated account addresses","description":"Returns a list of addresses associated with the authenticated user.","tags":["Account Management"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"A list of addresses for the authenticated user.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"eoaAccounts":{"type":"array","items":{"$ref":"#/components/schemas/EOAAccount"}}}}}}}}},"401":{"description":"Unauthorized, missing or invalid token."},"500":{"description":"Internal server error."}}},"post":{"summary":"Add a new account address for authentication","description":"Registers a new authenticated account address for the authenticated user.\nThis address can be used to sign in via SIWE and to start new API sessions.\n","tags":["Account Management"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"address":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","example":"0x1234567890abcdef1234567890abcdef12345678","description":"The Ethereum address of the new externally owned account."}}}}}},"responses":{"201":{"description":"Successfully created EOA account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EOAAccount"}}}},"400":{"description":"Invalid request body or address format."},"401":{"description":"Unauthorized, missing or invalid token."},"500":{"description":"Internal server error."}}}},"/api/v1/eoa-accounts/{id}":{"delete":{"summary":"Remove account address for authentication","description":"Removes the account address associated with the authenticated user.","tags":["Account Management"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"example":"0x1234567890abcdef1234567890abcdef12345678","description":"The ID of the externally owned account to be deleted."}],"responses":{"200":{"description":"Successfully deleted the EOA account.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","example":"clp3j1f9a0000a1cdh6ezx2qv"}}}}}}}},"400":{"description":"Invalid account ID format."},"401":{"description":"Unauthorized, missing or invalid token."},"403":{"description":"Forbidden. Cannot delete the last EOA account a user has."},"404":{"description":"Couldn't find a belonging EOA account."},"500":{"description":"Internal server error."}}}},"/api/v1/ibans/available":{"get":{"summary":"Check IBAN Availability","description":"Returns whether the user is eligible to enable an IBAN on their account.","tags":["IBAN"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"IBAN availability status for the user.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["available"],"properties":{"available":{"type":"boolean","description":"Indicates if the user is eligible to enable an IBAN."}}}},"example":{"data":{"available":true}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/ibans/signing-message":{"get":{"summary":"Get the message that needs to be signed for IBAN activation","description":"Returns the standard message that users need to sign with their wallet to verify ownership for Monerium IBAN activation.","tags":["IBAN"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successfully retrieved the signing message","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"message":{"type":"string","example":"I hereby declare that I am the address owner."}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/integrations/monerium":{"post":{"summary":"Create a new Monerium integration","description":"Creates a new Monerium integration for the authenticated user and associates it with the authenticated user's EOA address.\nAll operations on Monerium are done through their API, this endpoint is just a way to reuse the GP KYC to open an account on Monerium.\n\n- If the user does not have a Monerium account, this endpoint will create a new one and associate it with the authenticated user's EOA address.\n- If the user already has a Monerium account, you do not need to call this endpoint again.\n\nJust use the Monerium API directly to request access to the user's monerium account.\nCheck their documentation for more information: https://monerium.dev/api-docs/v2\n","tags":["IBAN"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"signature":{"type":"string","description":"Signature of the message \"I hereby declare that I am the address owner.\"\nThis signature is created by signing the message with the user's wallet.\nThe exact message can be retrieved from the /api/v1/ibans/signing-message endpoint.\nThe signature is used to verify ownership of the address on Monerium.\nFormat: Ethereum signature string (e.g., \"0x1234...\").\n"}}}}}},"responses":{"200":{"description":"Successfully created a new Monerium integration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoneriumIntegrationResponse"},"examples":{"success":{"summary":"Success","value":{"data":{"success":true,"status":200,"moneriumProfileId":"profile_123456789","iban":"DE44500105175407324931","bic":"GENODEM1GLS"}}}}}}},"400":{"description":"Validation error on Monerium side.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoneriumIntegrationResponse"},"examples":{"validation_error":{"summary":"Validation error on Monerium side","value":{"data":{"success":false,"status":400,"description":"Failed to create Monerium profile","responseData":{"code":400,"status":"Bad Request","message":"Validation errors","errors":{"firstName":"First name is missing"}},"responseHeaders":{"x-correlation-id":"1234567890"}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"User not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"user_not_found":{"summary":"User not found","value":{"message":"User not found"}}}}}},"422":{"description":"Validation errors on GP side.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"signer_address_required":{"summary":"Signer address is required","value":{"message":"Signer address is required"}},"validation_error":{"summary":"Signature is missing","value":{"message":"Invalid request data","errors":{"validation":"Signature is required"}}},"signer_address_not_verified":{"summary":"Signer address is not verified. The signer address needs to be a verified EOA address.","value":{"message":"Signer address is not verified"}}}}}},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/ibans/details":{"get":{"summary":"Retrieve IBAN details","description":"Returns IBAN details including the IBAN number, BIC, and Status.","deprecated":true,"tags":["IBAN"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successfully retrieved IBAN details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","required":["ibanStatus"],"properties":{"iban":{"type":"string","nullable":true,"example":"DE44500105175407324931"},"bic":{"type":"string","nullable":true,"example":"GENODEM1GLS"},"ibanStatus":{"type":"string","enum":["NOTSTARTED","PENDING","PENDING_OAUTH","ASSIGNED"],"example":"PENDING"},"address":{"type":"string","nullable":true,"example":"0x71C7656EC7ab88b098defB751B7401B5f6d8976F","description":"The blockchain address associated with this IBAN account"}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/ibans/orders":{"get":{"summary":"Retrieve a list of Monerium IBAN orders","description":"Returns a list of IBAN orders associated with the authenticated user.","tags":["IBAN"],"deprecated":true,"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"A list of Monerium IBAN orders","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/IbanOrder"}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/kyc/integration":{"get":{"summary":"Retrieve Link for Web Integration","description":"Retrieve the specification to follow with the KYC integration.","tags":["KYC"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"lang","schema":{"type":"string","pattern":"^[a-z]{2}$","example":"en"},"description":"Optional language code in ISO 639-1 format (2 letters) to force the KYC flow language. If not provided, SumSub will use its own rules to determine the language."}],"responses":{"200":{"description":"The KYC integration specification.","content":{"application/json":{"schema":{"type":"object","required":["type","url"],"properties":{"type":{"type":"string","enum":["SUMSUB_WEB"],"description":"The type of the KYC integration."},"url":{"type":"string","description":"The url that needs to be opened to follow through the SumSub KYC flow.","format":"url"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"409":{"description":"The user has already been approved","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the error.","example":"The user has already been approved"}}}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the server error.","example":"An unexpected error occurred."}}}}}}}}},"/api/v1/kyc/integration/sdk":{"get":{"summary":"Retrieve Access Token for Sumsub SDK Integration","description":"Retrieve the specification to follow with the KYC integration.","tags":["KYC"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"lang","schema":{"type":"string","pattern":"^[a-z]{2}$","example":"en"},"description":"Optional language code in ISO 639-1 format (2 letters) to force the KYC flow language. If not provided, SumSub will use its own rules to determine the language."}],"responses":{"200":{"description":"The KYC integration specification.","content":{"application/json":{"schema":{"type":"object","required":["type","token","userId"],"properties":{"type":{"type":"string","enum":["SUMSUB_SDK"],"description":"The type of the KYC integration."},"token":{"type":"string","description":"The token that needs to be used to follow through the SumSub KYC flow."},"userId":{"type":"string","description":"The user ID."}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"409":{"description":"The user has already been approved","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the error.","example":"The user has already been approved"}}}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the server error.","example":"An unexpected error occurred."}}}}}}}}},"/api/v1/kyc/import-partner-applicant":{"post":{"summary":"Retrieve a KYC Sharing Token for Sumsub Partners","tags":["KYC"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"forClientId":{"type":"string","example":"CoolCoinLtd"},"ttlInSecs":{"type":"number","example":600}}}}}},"responses":{"200":{"description":"Successfully retrieved Sumsub's reusable token.","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string"},"forClientId":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/order/{orderId}/create-card":{"post":{"tags":["Physical Card Order"],"summary":"Create a Physical Card","description":"The last step in the physical card creation process.\n\n**Note:** To apply a coupon code, use the `/api/v1/order/{orderId}/attach-coupon` endpoint before creating the card.\n\n**Validation Requirements:**\n- User must have completed KYC successfully\n- User must have a verified phone number\n- User must have name and address set\n- User's country must be supported\n- User must not have reached maximum active cards limit\n- Safe account should be setup\n- User must not have existing pending card orders\n- For paid cards, a valid transaction hash is required\n","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"orderId","required":true,"description":"The unique identifier of the card order.","schema":{"type":"string","example":"1234"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"pinData":{"type":"object","description":"Optional PIN data for the card","properties":{"encryptedKey":{"type":"string","description":"Encrypted key for PIN","example":"encryptedPinKey"},"encryptedPin":{"type":"string","description":"Encrypted PIN value","example":"encryptedPinData"},"iv":{"type":"string","description":"Initialization vector for encryption","example":"iv"}}},"transactionHash":{"type":"string","description":"Transaction hash for card payment. Required for paid cards.\nMust be in hexadecimal format (0x...).\n","pattern":"^0x[a-fA-F0-9]+$","example":"0x1234567890123456789012345678901234567890123456789012345678901234"}},"example":{"pinData":{"encryptedKey":"encryptedKey","encryptedPin":"encryptedPin","iv":"iv"},"transactionHash":"0x1234567890123456789012345678901234567890123456789012345678901234"}}}}},"responses":{"200":{"description":"The card was created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"cardToken":{"type":"string","description":"The token of the created card","example":"1234567890"}}},"example":{"success":true}}}},"400":{"description":"Bad request - validation errors","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message"}}},"examples":{"missingTransactionHash":{"summary":"Transaction hash not provided for paid card","value":{"error":"A transaction hash for the cost of the card was not provided"}}}}}},"401":{"description":"Unauthorized - user not found or not authenticated","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}},"example":{"error":"Unauthorized"}}}},"404":{"description":"Card order not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}},"example":{"error":"Order not found"}}}},"409":{"description":"Conflict - business rule violations","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message"}}},"examples":{"pendingOrder":{"summary":"User has existing pending card order","value":{"error":"User already has a card order in progress."}},"duplicateTransactionHash":{"summary":"Transaction hash already used","value":{"error":"The provided transaction hash has already been used for another card order."}}}}}},"422":{"description":"Unprocessable entity - validation criteria not met","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Validation error message"}}},"examples":{"kycNotComplete":{"summary":"KYC not completed","value":{"error":"User needs to complete KYC successfully."}},"invalidRiskScore":{"summary":"User has incompatible risk score","value":{"error":"User has incompatible risk score."}},"phoneNotVerified":{"summary":"Phone number not verified","value":{"error":"User does not have a verified phone number."}},"nameNotSet":{"summary":"User name not set","value":{"error":"User's name is not set"}},"addressNotSet":{"summary":"User address not set","value":{"error":"User's address is not set"}},"countryNotSupported":{"summary":"User's country not supported","value":{"error":"User's country is not supported"}},"maxCardsReached":{"summary":"Maximum active cards reached","value":{"error":"User has reached the maximum number of active cards (3)."}},"safeNotReady":{"summary":"Safe account not ready","value":{"error":"Could not create card due to safe misconfiguration"}}}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message"}}},"example":{"error":"Something went wrong"}}}}}}},"/api/v1/order/{orderId}/attach-transaction":{"put":{"tags":["Physical Card Order"],"summary":"Register payment for a Physical Card Order","description":"This endpoint associates a provided on-chain transaction hash with an existing card order by its `orderId`. If the card is free, you can skip this step.","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"orderId","required":true,"description":"The unique identifier of the card order to which the transaction will be attached.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["transactionHash"],"properties":{"transactionHash":{"type":"string","description":"The on-chain transaction hash to be attached.","example":"0x123abc..."}}}}}},"responses":{"200":{"description":"Transaction successfully attached to the card order.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","description":"Indicates if the operation was successful.","example":true}}}}}},"400":{"description":"Invalid transaction or hash already used.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the error.","example":"Invalid transaction provided (already used)."}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Card order not found.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the error.","example":"Card order not found."}}}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the server error.","example":"An unexpected error occurred."}}}}}}}}},"/api/v1/order/{orderId}/attach-coupon":{"post":{"tags":["Physical Card Order"],"summary":"Attach a coupon to a Physical Card Order","description":"This endpoint associates a provided coupon code with an existing card order by its `orderId`. Use the `GPDOCS` coupon code to get the card for free.","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"orderId","required":true,"description":"The unique identifier of the card order to which the coupon will be attached.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["couponCode"],"properties":{"couponCode":{"type":"string","description":"The coupon code to be applied to the order.","example":"DISCOUNT2023"}}}}}},"responses":{"200":{"description":"Coupon successfully attached to the card order.","content":{"application/json":{"schema":{"type":"object","properties":{"couponCode":{"type":"string","description":"The coupon code that was applied to the order.","example":"DISCOUNT2023"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Card order not found.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the error.","example":"Card order not found."}}}}}},"422":{"description":"Coupon code is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the error.","example":"Coupon code is invalid."}}}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the server error.","example":"An unexpected error occurred."}}}}}}}}},"/api/v1/order/{orderId}":{"get":{"tags":["Physical Card Order"],"summary":"Retrieve details of a Physical Card Order","description":"This endpoint retrieves details of a card order by its `orderId`.","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"orderId","required":true,"description":"The unique identifier of the card order.","schema":{"type":"string"}}],"responses":{"200":{"description":"Successfully retrieved card order details.","content":{"application/json":{"schema":{"type":"object","required":["id","userId","status","personalizationSource","totalDiscountEUR","createdAt"],"properties":{"id":{"type":"string","format":"uuid","description":"The unique identifier of the card order.","example":"123e4567-e89b-12d3-a456-426614174000"},"transactionHash":{"type":"string","nullable":true,"description":"The on-chain transaction hash associated with the order.","example":"0x123abc..."},"embossedName":{"type":"string","nullable":true,"description":"The name embossed on the card.","example":"John Doe"},"address1":{"type":"string","nullable":true,"description":"The first line of the shipping address."},"address2":{"type":"string","nullable":true,"description":"The second line of the shipping address."},"city":{"type":"string","nullable":true,"description":"The city of the shipping address."},"postalCode":{"type":"string","nullable":true,"description":"The postal code of the shipping address."},"state":{"type":"string","nullable":true,"description":"The state of the shipping address."},"country":{"type":"string","nullable":true,"description":"The country of the shipping address."},"userId":{"type":"string","description":"The user id for this card order."},"status":{"type":"string","description":"Current order status","enum":["PENDINGTRANSACTION","TRANSACTIONCOMPLETE","CONFIRMATIONREQUIRED","READY","CARDCREATED","FAILEDTRANSACTION","CANCELLED"]},"personalizationSource":{"type":"string","enum":["KYC","ENS"]},"couponCode":{"type":"string","description":"The coupon code tied to this card order","example":"DISCOUNT2023"},"totalAmountEUR":{"type":"number","nullable":true,"example":20.99},"totalDiscountEur":{"type":"number","example":1.99},"createdAt":{"type":"string","description":"When the order was created","format":"date-time","example":"2023-01-09T13:45:30Z"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Card order not found.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the error.","example":"Card order not found."}}}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the server error.","example":"An unexpected error occurred."}}}}}}}}},"/api/v1/order/{orderId}/confirm-payment":{"put":{"tags":["Physical Card Order"],"summary":"Confirm the payment for a Physical Card Order","description":"This endpoint marks the Card Order with `orderId` as paid. Even if the card is free, you need to call this endpoint to confirm the payment.","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"orderId","required":true,"description":"The unique identifier of the card order.","schema":{"type":"string"}}],"responses":{"200":{"description":"Transaction successfully attached to the card order.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","description":"Indicates if the operation was successful.","example":true}}}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"message":{"type":"string","description":"Card Order is not in the correct status.","example":"Card Order is not in the correct status"}}},{"type":"object","properties":{"message":{"type":"string","description":"No transaction hash found for this order.","example":"No transaction hash found for this order"}}},{"type":"object","properties":{"message":{"type":"string","description":"Could not find payment in transaction hash.","example":"Could not find payment in transaction hash"}}}]}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Card order not found.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the error.","example":"Card order not found."}}}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the server error.","example":"An unexpected error occurred."}}}}}}}}},"/api/v1/order/{orderId}/cancel":{"post":{"tags":["Physical Card Order"],"summary":"Cancel a Physical Card Order","description":"This endpoint transitions the card order to the cancelled state.","security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"orderId","required":true,"description":"The unique identifier of the card order to cancel.","schema":{"type":"string"}}],"responses":{"200":{"description":"Card order successfully cancelled.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","example":true}}}}}},"400":{"description":"Invalid order transition or order not in cancellable state.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Invalid order transition"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Card order not found.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Card order not found."}}}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"An unexpected error occurred."}}}}}}}}},"/api/v1/order/create":{"post":{"tags":["Physical Card Order"],"summary":"Create Physical Card Order","description":"Orders a new physical card for the authenticated user.\nThis is the first step in the physical card order process, the card is not created yet.\n\nNext are the steps to complete the order:\n1. Optionally attach a coupon using `/api/v1/order/{orderId}/attach-coupon` (use the `GPDOCS` coupon code to get the card for free)\n2. If not free, attach a transaction hash using `/api/v1/order/{orderId}/attach-transaction`\n3. Confirm the payment using `/api/v1/order/{orderId}/confirm-payment`\n4. Create the card using `/api/v1/order/{orderId}/create-card`\n","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"personalizationSource":{"type":"string","enum":["ENS"]},"ENSName":{"type":"string","maxLength":24},"shippingAddress":{"type":"object","nullable":true,"properties":{"address1":{"type":"string","maxLength":50},"address2":{"type":"string","nullable":true,"maxLength":50},"city":{"type":"string"},"postalCode":{"type":"string"},"country":{"type":"string","description":"Two-letter country code per ISO 3166-1 alpha-2 (e.g., \"BR\", \"DE\").","example":"BR"}},"required":["address1","city","postalCode","country"]},"virtual":{"type":"boolean","default":false}},"required":["personalizationSource","ENSName"]},{"type":"object","properties":{"personalizationSource":{"type":"string","enum":["KYC"]},"shippingAddress":{"type":"object","nullable":true,"properties":{"address1":{"type":"string","maxLength":50},"address2":{"type":"string","nullable":true,"maxLength":50},"city":{"type":"string"},"postalCode":{"type":"string"},"country":{"type":"string","description":"Two-letter country code per ISO 3166-1 alpha-2 (e.g., \"BR\", \"DE\").","example":"BR"}},"required":["address1","city","postalCode","country"]},"virtual":{"type":"boolean","default":false}},"required":["personalizationSource"]}]}}}},"responses":{"200":{"description":"Card order created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardOrder"}}}},"400":{"description":"Bad Request - One of several possible client errors","content":{"application/json":{"schema":{"type":"string","enum":["Error: There is already a pending card order","Error: User is not approved through KYC","Error: Unknown personalization source","Error: Shipping needs to be done to the user's country"]}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/owners":{"get":{"summary":"List Safe Owners","description":"Returns the list of addresses that are owners of the user's Safe account.\nThese owners have the ability to sign transactions and manage the Safe.\n","tags":["Safe Management"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successfully retrieved the list.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["owners"],"properties":{"owners":{"type":"array","items":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"Ethereum address of a Safe owner.","example":"0x3270bf32AB647e90eF94A026c70Aa1daaaDA2382"}}}}}}}}},"401":{"description":"Unauthorized - invalid or missing authentication token.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Authentication error message.","example":"Unauthorized"}}}}}},"404":{"description":"Safe account not found for the user.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Error message explaining why the request failed.","example":"Couldn't find associated Safe for the user"}}}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the server error.","example":"An unexpected error occurred."}}}}}}}},"post":{"summary":"Add Safe Owner","description":"Adds a new owner to the user's Safe account.\n\nThe signature should be generated by signing the transaction data obtained from\nthe `/api/v1/owners/add/transaction-data` endpoint.\n\nThe operation is processed through a delay relay mechanism that executes after 3 minutes.\n","tags":["Safe Management"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["newOwner","signature","message"],"properties":{"newOwner":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"The address to add as a new Safe owner.","example":"0x3270bf32AB647e90eF94A026c70Aa1daaaDA2382"},"signature":{"type":"string","description":"The wallet signature authorizing this operation.","example":"0x1234567890abcdef..."},"message":{"type":"object","required":["salt","data"],"description":"The message object containing transaction data and salt.","properties":{"salt":{"type":"string","description":"The salt value used in the EIP-712 typed data.","example":"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"},"data":{"type":"string","description":"The encoded transaction data from the typed data message.","example":"0xa9059cbb0000000000000000000000003270bf32ab647e90ef94a026c70aa1daaaada2382"}}},"smartWalletAddress":{"type":"string","description":"Optional. If using a smart account, the address of the smart wallet to use for the operation.","example":"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"}}}}}},"responses":{"200":{"description":"Successfully submitted the add owner request.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/DelayTransaction"}}}}}},"401":{"description":"Unauthorized - invalid or missing authentication token."},"404":{"description":"Safe account not found for the user."},"422":{"description":"Unprocessable Entity - validation errors in request body.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Details about the validation error.","example":"Invalid newOwner address format"}}}}}},"500":{"description":"Internal server error."}}},"delete":{"summary":"Remove Safe Owner","description":"Removes an existing owner from the user's Safe account.\n\nThe signature should be generated by signing the transaction data obtained from\nthe `/api/v1/owners/remove/transaction-data` endpoint.\n\nThe operation is processed through a delay relay mechanism that executes after 3 minutes.\n","tags":["Safe Management"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ownerToRemove","signature","message"],"properties":{"ownerToRemove":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"The address to remove from Safe owners.","example":"0x3270bf32AB647e90eF94A026c70Aa1daaaDA2382"},"signature":{"type":"string","description":"The wallet signature authorizing this operation.","example":"0x1234567890abcdef..."},"message":{"type":"object","required":["salt","data"],"description":"The message object containing transaction data and salt.","properties":{"salt":{"type":"string","description":"The salt value used in the EIP-712 typed data.","example":"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"},"data":{"type":"string","description":"The encoded transaction data from the typed data message.","example":"0xa9059cbb0000000000000000000000003270bf32ab647e90ef94a026c70aa1daaaada2382"}}},"smartWalletAddress":{"type":"string","description":"Optional. If using a smart account, the address of the smart wallet to use for the operation.","example":"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"}}}}}},"responses":{"200":{"description":"Successfully submitted the remove owner request.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/DelayTransaction"}}}}}},"401":{"description":"Unauthorized - invalid or missing authentication token."},"404":{"description":"Safe account not found for the user."},"422":{"description":"Unprocessable Entity - validation errors in request body.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Details about the validation error.","example":"Invalid ownerToRemove address format"}}}}}},"500":{"description":"Internal server error."}}}},"/api/v1/owners/add/transaction-data":{"get":{"summary":"Get typed data for adding a Safe Owner","description":"Returns the EIP-712 typed data that needs to be signed by the user's wallet to add a new owner to the Safe.\nThis endpoint is used as part of a three-step process:\n1. Call this endpoint to get the EIP-712 typed data\n2. Sign the typed data with the user's wallet using EIP-712 signature standard\n3. Submit the signature to the POST `/api/v1/owners` endpoint\n","tags":["Safe Management"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"newOwner","required":true,"description":"The address to add as a new Safe owner.","schema":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"},"example":"0x3270bf32AB647e90eF94A026c70Aa1daaaDA2382"}],"responses":{"200":{"description":"Successfully retrieved EIP-712 typed data for signing.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["domain","primaryType","types","message"],"properties":{"domain":{"type":"object","required":["verifyingContract","chainId"],"properties":{"verifyingContract":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"The contract address that will verify the signature.","example":"0x3270bf32AB647e90eF94A026c70Aa1daaaDA2382"},"chainId":{"type":"number","description":"The chain ID for the network.","example":100}}},"primaryType":{"type":"string","enum":["ModuleTx"],"description":"The primary type for EIP-712 typed data signing.","example":"ModuleTx"},"types":{"type":"object","required":["ModuleTx"],"properties":{"ModuleTx":{"type":"array","description":"Array of type definitions for the ModuleTx structure.","items":{"type":"object","required":["type","name"],"properties":{"type":{"type":"string","description":"The field type.","example":"bytes"},"name":{"type":"string","description":"The field name.","example":"data"}}}}}},"message":{"type":"object","required":["data","salt"],"properties":{"data":{"type":"string","description":"The encoded transaction data for adding an owner.","example":"0xa9059cbb0000000000000000000000003270bf32ab647e90ef94a026c70aa1daaaada2382"},"salt":{"type":"string","description":"The salt value for the typed data.","example":"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"}}}}}}}}}},"401":{"description":"Unauthorized - invalid or missing authentication token."},"404":{"description":"Safe account not found for the user."},"422":{"description":"Unprocessable Entity - validation errors in query parameters."},"500":{"description":"Internal server error."}}}},"/api/v1/owners/remove/transaction-data":{"get":{"summary":"Get typed data for removing a Safe Owner","description":"Returns the EIP-712 typed data that needs to be signed by the user's wallet to remove an owner from the Safe.\nThis endpoint is used as part of a three-step process:\n1. Call this endpoint to get the EIP-712 typed data\n2. Sign the typed data with the user's wallet using EIP-712 signature standard\n3. Submit the signature to the DELETE `/api/v1/owners` endpoint\n","tags":["Safe Management"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"query","name":"ownerToRemove","required":true,"description":"The address to remove.","schema":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"},"example":"0x3270bf32AB647e90eF94A026c70Aa1daaaDA2382"}],"responses":{"200":{"description":"Successfully retrieved EIP-712 typed data for signing.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["domain","primaryType","types","message"],"properties":{"domain":{"type":"object","required":["verifyingContract","chainId"],"properties":{"verifyingContract":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$","description":"The contract address that will verify the signature.","example":"0x3270bf32AB647e90eF94A026c70Aa1daaaDA2382"},"chainId":{"type":"number","description":"The chain ID for the network.","example":100}}},"primaryType":{"type":"string","enum":["ModuleTx"],"description":"The primary type for EIP-712 typed data signing.","example":"ModuleTx"},"types":{"type":"object","required":["ModuleTx"],"properties":{"ModuleTx":{"type":"array","description":"Array of type definitions for the ModuleTx structure.","items":{"type":"object","required":["type","name"],"properties":{"type":{"type":"string","description":"The field type.","example":"bytes"},"name":{"type":"string","description":"The field name.","example":"data"}}}}}},"message":{"type":"object","required":["data","salt"],"properties":{"data":{"type":"string","description":"The encoded transaction data for removing an owner.","example":"0xa9059cbb0000000000000000000000003270bf32ab647e90ef94a026c70aa1daaaada2382"},"salt":{"type":"string","description":"The salt value for the typed data.","example":"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"}}}}}}}}}},"401":{"description":"Unauthorized - invalid or missing authentication token."},"404":{"description":"Safe account not found for the user."},"422":{"description":"Unprocessable Entity - validation errors in query parameters."},"500":{"description":"Internal server error."}}}},"/api/v1/rewards":{"get":{"summary":"Retrieve Rewards Information","description":"Returns user's OG status, GNO balance of Safe, and calculated base cashback rate.\nNote that the cashbackRate returned does not include the +1% bonus for OG NFT holders - to get the total cashback rate, add 1% to the cashbackRate if isOg is true.\n","tags":["Rewards"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successfully retrieved rewards information","content":{"application/json":{"schema":{"type":"object","required":["isOg","gnoBalance","cashbackRate"],"properties":{"isOg":{"type":"boolean","description":"Indicates if the user holds an OG NFT token. If true, the user gets an additional 1% cashback on top of the base cashbackRate.","example":true},"gnoBalance":{"type":"number","description":"User's GNO token balance in their Safe account","example":10.5},"cashbackRate":{"type":"number","description":"Base cashback rate calculated from GNO balance (0-4%). For OG NFT holders, add 1% to this rate to get the total cashback rate.","example":2.5}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/api/v1/terms":{"get":{"tags":["Terms"],"summary":"Retrieve all Terms and Conditions","description":"This endpoint provides public access to terms information including type,\ncurrent version, URL, and name.\n","responses":{"200":{"description":"Successfully retrieved terms","content":{"application/json":{"schema":{"type":"object","properties":{"terms":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["general-tos","card-monavate-tos","cashback-tos","privacy-policy","monavate-privacy-policy"],"description":"Type of terms and conditions"},"currentVersion":{"type":"string","description":"Current version of these terms"},"url":{"type":"string","description":"URL to view these terms"},"name":{"type":"string","description":"Human-readable name of these terms"}}}}}},"example":{"terms":[{"type":"general-tos","currentVersion":"TOS_GENERAL_VERSION_1","url":"https://help.gnosispay.com/hc/en-us/articles/43350967419412-Gnosis-Pay-Terms-of-Service","name":"Gnosis Pay Terms of Service"},{"type":"card-monavate-tos","currentVersion":"TOS_CARD_VERSION_1","url":"https://help.gnosispay.com/hc/en-us/categories/41384871493524-Legal-Terms-and-Policies","name":"Monavate Cardholder Terms"},{"type":"cashback-tos","currentVersion":"TOS_CASHBACK_2024-08-01","url":"https://forum.gnosis.io/t/gip-110-should-the-gnosis-dao-create-and-fund-a-gnosis-pay-rewards-program-with-10k-gno/8837","name":"Cashback Terms"},{"type":"privacy-policy","currentVersion":"PRIVACY_POLICY_VERSION_1","url":"https://help.gnosispay.com/hc/en-us/articles/39723694982548-Gnosis-Pay-Privacy-and-Cookies-Policy","name":"Privacy and Cookies Policy"},{"type":"monavate-privacy-policy","currentVersion":"MONAVATE_PRIVACY_POLICY_VERSION_1","url":"https://www.monavate.com/privacy-policy","name":"Monavate Privacy Policy"}]}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/user/card-public-key":{"get":{"summary":"Get card public key","deprecated":true,"tags":["User"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successfully retrieved the card public key","content":{"application/json":{"schema":{"type":"object","required":["publicKey"],"properties":{"publicKey":{"type":"string","description":"The public key for the card based on the user's country","example":"0x1234567890abcdef1234567890abcdef12345678"}}}}}},"400":{"description":"Bad request - user has no country set","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"User has no country set"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Unauthorized"}}}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"No user found"}}}}}},"500":{"description":"Internal server error.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Details about the server error.","example":"An unexpected error occurred."}}}}}}}}},"/api/v1/user/terms":{"get":{"tags":["User"],"security":[{"bearerAuth":[]}],"summary":"Retrieve Terms and Conditions Status","description":"Returns the status of all terms and conditions, including whether the user has accepted\nthe latest version, when they were accepted, and links to the terms documents.\n","responses":{"200":{"description":"Successfully retrieved terms status","content":{"application/json":{"schema":{"type":"object","properties":{"terms":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["general-tos","card-monavate-tos","cashback-tos","privacy-policy"],"description":"Type of terms and conditions"},"currentVersion":{"type":"string","description":"Current version of these terms"},"accepted":{"type":"boolean","description":"Whether the user has accepted the current version"},"acceptedVersion":{"type":"string","nullable":true,"description":"Version the user has accepted (if any)"},"acceptedAt":{"type":"string","format":"date-time","nullable":true,"description":"When the user accepted these terms"},"url":{"type":"string","description":"URL to view these terms"}}}}}},"example":{"terms":[{"type":"general-tos","currentVersion":"TOS_GENERAL_VERSION_1","accepted":true,"acceptedVersion":"TOS_GENERAL_VERSION_1","acceptedAt":"2024-08-20T12:34:56Z","url":"https://help.gnosispay.com/hc/en-us/articles/39723036951444-Gnosis-Pay-WebApp-Terms-of-Service"},{"type":"card-monavate-tos","currentVersion":"TOS_CARD_VERSION_1","accepted":false,"url":"https://help.gnosispay.com/hc/en-us/articles/39726634253076-Monavate-Cardholder-Terms-EEA"},{"type":"cashback-tos","currentVersion":"TOS_CASHBACK_2024-08-01","accepted":false,"url":"https://forum.gnosis.io/t/gip-110-should-the-gnosis-dao-create-and-fund-a-gnosis-pay-rewards-program-with-10k-gno/8837"}]}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"422":{"description":"Request validation error","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}},"example":{"message":"Error: User not found"}}}},"500":{"$ref":"#/components/responses/InternalServerError"}}},"post":{"tags":["User"],"security":[{"bearerAuth":[]}],"summary":"Accept Terms and Conditions","description":"Accept specific terms and conditions based on type and version.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TermsBody"}}}},"responses":{"200":{"description":"Terms accepted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}},"example":{"ok":true}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"422":{"description":"Validation error","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}},"examples":{"invalidVersion":{"value":{"message":"Invalid version for the selected terms type"}},"alreadyAccepted":{"value":{"message":"You have already accepted these terms"}}}}}},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/user":{"get":{"tags":["User"],"security":[{"bearerAuth":[]}],"summary":"Retrieve User profile","description":"Get the User profile information.","responses":{"200":{"description":"Successfully retrieved User profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"422":{"description":"Request validation error","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}},"example":{"message":"Error: User not found"}}}},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/webhooks/message/{partnerId}":{"get":{"tags":["Webhooks"],"summary":"Retrieve Message to Sign for Webhook Subscription","description":"Generates a message for the user to sign. This message must be sent on `POST /api/v1/webhooks/subscribe/{partnerId}` to subscribe to webhook notifications.","parameters":[{"in":"path","name":"partnerId","required":true,"schema":{"type":"string"},"description":"Partner ID to subscribe to"},{"in":"query","name":"walletAddress","required":false,"schema":{"type":"string","pattern":"^0x[a-fA-F0-9]{40}$"},"description":"Optional Ethereum wallet address to use for signing. Must be one of the user's verified EOA addresses. If not provided, defaults to the user's primary verified wallet."}],"responses":{"200":{"description":"Message generated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"SIWE message to be signed by the user"},"nonce":{"type":"string","description":"Unique nonce for this subscription request"}}}}}},"400":{"description":"Wallet address does not belong to user"},"401":{"description":"Authentication required"},"404":{"description":"Partner not found"},"422":{"description":"Invalid wallet address format"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/webhooks/subscribe/{partnerId}":{"post":{"tags":["Webhooks"],"summary":"Subscribe to Webhooks","description":"Allows a partner to receive webhook notifications for the authenticated user.","parameters":[{"in":"path","name":"partnerId","required":true,"schema":{"type":"string"},"description":"Partner ID to subscribe to"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["message","signature"],"properties":{"message":{"type":"string","description":"SIWE message obtained from /api/v1/webhooks/message/{partnerId}"},"signature":{"type":"string","description":"Signature of the message by the user's wallet"}}}}}},"responses":{"200":{"description":"Successfully subscribed to partner webhooks","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Whether the subscription was successful"},"subscriptionId":{"type":"string","description":"Unique ID of the created subscription"}}}}}},"400":{"description":"Invalid request or signature"},"401":{"description":"Authentication required"},"409":{"description":"Subscription already exists"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/api/v1/webhooks/subscription/{partnerId}":{"get":{"tags":["Webhooks"],"summary":"Check if authenticated user is subscribed to partner webhooks","description":"Allows the authenticated user to check if they are subscribed to a partner's webhook notifications.","parameters":[{"in":"path","name":"partnerId","required":true,"schema":{"type":"string"},"description":"Partner ID to check subscription for"}],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Subscription status retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"subscribed":{"type":"boolean","description":"Whether the authenticated user is subscribed to the partner's webhooks"},"subscriptionId":{"type":"string","nullable":true,"description":"ID of the subscription if it exists"}}}}}},"401":{"description":"Authentication required"},"404":{"description":"Partner not found"},"500":{"$ref":"#/components/responses/InternalServerError"}}}}}}