{
    "openapi": "3.1.0",
    "info": {
        "title": "Payments API",
        "version": "2026-10-26",
        "description": "Merchant API. Create and read deposits and withdrawals, simulate them in test mode, receive signed webhooks. Errors are RFC 9457 problem+json with a readable `code`."
    },
    "servers": [
        {
            "url": "https:\/\/api.no1paytest.com\/v1"
        }
    ],
    "security": [
        {
            "secret_key": []
        }
    ],
    "paths": {
        "\/deposits": {
            "post": {
                "operationId": "v1.deposits.store",
                "description": "Returns the deposit and `payment_url`: the payment page link to send the customer to.\nSending the same Idempotency-Key with the same body again returns the same deposit (and the same\n`payment_url`) with the header `Idempotent-Replayed: true`; the same key with another body (another\namount, `reference`, \u2026) is refused.\n\nSend your order id as `reference` to match the deposit with your order; it comes back on the deposit and in\nevery webhook. A new deposit has `version` 1; every status change adds 1 (see the deposit object).\n\nSend `method` and the customer goes straight to that method's page and cannot switch. Leave it out and the\ndeposit starts as `waiting_for_method`: the customer picks on our payment page, from the methods that work now\nfor them and the amount (narrow the list with `allowed_methods`), and may go back and pick another until money\nmay move. `webhook_url` is required: every webhook of this deposit goes to it, and only to it.\n\nThe key decides the mode: a test key (`sk_test_\u2026`) makes a test deposit (`mode: test`), which never moves\nreal money: its payment page shows a test payee and buttons to end it, and you can end it with\n`POST \/v1\/deposits\/{id}\/simulate`. A live key (`sk_live_\u2026`) makes a live deposit once live mode is turned on\nfor your account. Idempotency-Keys and customers are separate in each mode.\n\nA test deposit's payment page takes only the test data of the guide (Test data): a card-to-card one only the test\ncards and test codes, each with a fixed outcome; a bank account transfer or pol one only the test tracking numbers\n(paid or failed at once, or nothing) and a test Sheba as the customer's own. A live payment page refuses a test card\nand a test Sheba.",
                "summary": "Create a deposit",
                "tags": [
                    "Deposit"
                ],
                "parameters": [
                    {
                        "name": "Idempotency-Key",
                        "in": "header",
                        "required": true,
                        "description": "Your unique key for this deposit, e.g. your order id or a UUID. 1 to 255 printable ASCII characters.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "order-10542"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "$ref": "#\/components\/schemas\/NewDeposit"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "id": {
                                            "type": "string",
                                            "examples": [
                                                "dep_01k6c3s0v1m2n3p4q5r6s7t8v9"
                                            ]
                                        },
                                        "object": {
                                            "type": "string",
                                            "const": "deposit"
                                        },
                                        "mode": {
                                            "description": "`test` or `live`: the mode of the key that created the deposit. A test deposit never moves real money:\nonly the simulator ends it. Test webhooks are signed with the test webhook secret, live ones with the\nlive secret (each goes to the `webhook_url` of its own deposit), so verify with the secret of `mode` before you deliver an order, or confirm with `GET \/v1\/deposits\/{id}` using your live key (a live key\nnever finds a test deposit).",
                                            "$ref": "#\/components\/schemas\/Mode"
                                        },
                                        "status": {
                                            "description": "waiting_for_method: the customer has not picked a method yet; pending: waiting for the customer's\npayment; paid: money received, credit the order; failed, expired: not paid, but a late payment can\nstill make them paid; cancelled: not paid, final (webhook `deposit.cancelled`); unknown: an operator is\nchecking a payment whose result is not clear (no webhook when it becomes unknown: the next one,\n`deposit.paid` or `deposit.failed`, says how it was settled).\nAn unpaid deposit becomes expired within about a minute after `expires_at` (webhook `deposit.expired`).\nA `card_to_card` deposit also expires earlier when the customer does nothing on the payment page for\nyour card idle minutes (10 by default), and is never expired while its card transfer is being made or\nchecked: it can stay pending past `expires_at`.",
                                            "$ref": "#\/components\/schemas\/DepositStatus"
                                        },
                                        "method": {
                                            "anyOf": [
                                                {
                                                    "description": "The method the customer pays with: the one you sent, or the one the customer picked on our payment page;\nnull while the status is waiting_for_method (the customer may also go back and pick another, until money\nmay move, so it can change while the deposit is pending and a method was not sent).\n| |\n|---|\n| `account_transfer` <br\/> Bank account transfer: the customer transfers to the merchant's bank account. |\n| `pol_transfer` <br\/> Pol transfer to the merchant's account (Sheba). |\n| `card_to_card` <br\/> Card-to-card transfer. |\n| `bank_gateway` <br\/> Iranian bank payment gateway. |",
                                                    "$ref": "#\/components\/schemas\/DepositMethod"
                                                },
                                                {
                                                    "type": "null"
                                                }
                                            ]
                                        },
                                        "amount": {
                                            "type": "integer",
                                            "description": "Amount in `currency`, as you sent it."
                                        },
                                        "currency": {
                                            "$ref": "#\/components\/schemas\/Currency"
                                        },
                                        "amount_rials": {
                                            "type": "integer",
                                            "description": "The amount in rials."
                                        },
                                        "fee_rials": {
                                            "type": [
                                                "integer",
                                                "null"
                                            ],
                                            "description": "Our fee in rials, set when the deposit is paid; null before."
                                        },
                                        "reference": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "Your own order id from the create request, or null.",
                                            "examples": [
                                                "order-10542"
                                            ]
                                        },
                                        "customer": {
                                            "type": "object",
                                            "description": "`id`: your own id for the customer. `level`: the name of the customer's user level used for this\ndeposit (a level set for the customer in your panel, else the `customer.level` you sent, else your\ndefault level); null only on deposits made before user levels existed.",
                                            "properties": {
                                                "id": {
                                                    "type": "string"
                                                },
                                                "level": {
                                                    "type": [
                                                        "string",
                                                        "null"
                                                    ]
                                                }
                                            },
                                            "required": [
                                                "id",
                                                "level"
                                            ]
                                        },
                                        "payer": {
                                            "description": "Who paid and from where, in full (never in a webhook): `card_number` is the card the customer paid from\n(a `card_to_card` deposit whose card form was sent; null otherwise), `account` the account number or Sheba\nthe customer typed on a bank transfer page (null otherwise), `bank` that account's bank (null when we do\nnot know it). Webhooks never carry this object: read it with `GET \/v1\/deposits\/{id}`.",
                                            "anyOf": [
                                                {
                                                    "type": "object",
                                                    "properties": {
                                                        "card_number": {
                                                            "type": [
                                                                "string",
                                                                "null"
                                                            ]
                                                        },
                                                        "account": {
                                                            "type": [
                                                                "string",
                                                                "null"
                                                            ]
                                                        },
                                                        "bank": {
                                                            "type": [
                                                                "string",
                                                                "null"
                                                            ]
                                                        }
                                                    },
                                                    "required": [
                                                        "card_number",
                                                        "account",
                                                        "bank"
                                                    ]
                                                },
                                                {
                                                    "type": "object"
                                                }
                                            ]
                                        },
                                        "redirect_url": {
                                            "type": "string"
                                        },
                                        "webhook_url": {
                                            "type": "string",
                                            "description": "Where this deposit's webhooks are sent: the `webhook_url` of the create request, fixed for the deposit\n(there is no general webhook URL). \"Send again\" uses it too. Each event is sent once unless you turn on\nAutomatic retries in your panel."
                                        },
                                        "allowed_methods": {
                                            "type": [
                                                "array",
                                                "null"
                                            ],
                                            "description": "The `allowed_methods` of the create request, in our order; null when it was not sent (the customer\ncould pick any method that works now, or you sent `method`).",
                                            "items": {
                                                "$ref": "#\/components\/schemas\/DepositMethod"
                                            }
                                        },
                                        "failure_code": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "Why the deposit was not paid, as a readable code from the error code list: `deposit_expired` when\nit expired, `payment_failed` when the payment did not go through, `gateway_unavailable` when no bank\ngateway could take a `bank_gateway` payment, `card_transfer_failed` when a `card_to_card` transfer\ncould not be made (no money moved), `method_unavailable` when no card transfer could start right now,\n`deposit_cancelled` when the customer cancelled the payment. Null while it is open, and null again once\nit is paid (also when an expired deposit is paid late).",
                                            "examples": [
                                                "deposit_expired"
                                            ]
                                        },
                                        "failure_message": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "A short English text for `failure_code`; null when `failure_code` is null.",
                                            "examples": [
                                                "The deposit expired before it was paid"
                                            ]
                                        },
                                        "version": {
                                            "type": "integer",
                                            "description": "Starts at 1 and increases by 1 on every status change. Ignore a webhook whose version is lower\nthan one you already processed for this deposit. An expired or failed deposit can still become\npaid, so always credit the order on deposit.paid.",
                                            "examples": [
                                                2
                                            ]
                                        },
                                        "created_at": {
                                            "type": "string"
                                        },
                                        "updated_at": {
                                            "type": "string",
                                            "description": "When anything on the deposit last changed."
                                        },
                                        "expires_at": {
                                            "type": "string",
                                            "description": "When the deposit expires if it is not paid by then. A `card_to_card` deposit may expire before it, when\nthe customer does nothing on the payment page for your card idle minutes (10 by default), and never\nexpires while its card transfer is being made or checked (it can stay pending past this time). For a\ndeposit made without `method` it is set again when the customer picks one: the picked method's own time,\nnever more than 2 hours after the deposit was made, so read it from `GET` or the webhook, not only from the\ncreate answer."
                                        },
                                        "paid_at": {
                                            "type": [
                                                "string",
                                                "null"
                                            ]
                                        },
                                        "payment_url": {
                                            "type": "string"
                                        }
                                    },
                                    "required": [
                                        "id",
                                        "object",
                                        "mode",
                                        "status",
                                        "method",
                                        "amount",
                                        "currency",
                                        "amount_rials",
                                        "fee_rials",
                                        "reference",
                                        "customer",
                                        "payer",
                                        "redirect_url",
                                        "webhook_url",
                                        "allowed_methods",
                                        "failure_code",
                                        "failure_message",
                                        "version",
                                        "created_at",
                                        "updated_at",
                                        "expires_at",
                                        "paid_at",
                                        "payment_url"
                                    ]
                                }
                            }
                        },
                        "headers": {
                            "Idempotent-Replayed": {
                                "description": "Present (\"true\") when this response is a replay of an earlier request with the same Idempotency-Key.",
                                "schema": {
                                    "type": "string"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "`authentication_failed`: Authentication failed. Send a valid secret key in the Authorization header: \"Bearer sk_live_\u2026\" or \"Bearer sk_test_\u2026\".",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "`customer_blocked`: This customer is blocked. The customer (customer.id) is blocked in your panel (Customers), so they cannot make new deposits or get new withdrawals. Unblock them in the panel if this was a mistake. Test and live customers are blocked separately.\n\n`customer_method_blocked`: This customer is blocked from this payment method. The customer (customer.id) is blocked from this method (method) in your panel (Customers), so they cannot make a deposit with it, or blocked from withdrawals, so they cannot get a new withdrawal. Offer the customer another method, or remove the block in the panel if this was a mistake. Test and live customers are blocked separately.\n\n`live_mode_disabled`: Live mode is not turned on for this merchant. Your live keys (sk_live_\u2026) work once live mode is turned on for your merchant account; ask us to turn it on when your integration is ready. Until then use a test key (sk_test_\u2026): test deposits never move real money.\n\n`ip_not_allowed`: This key may not be used from this IP address. The key has an IP allowlist (set per key in your panel: Developers, IP allowlist) and the call came from an address that is not on it; the detail names that address. Call from one of your listed servers, or add the address (or its range) to the key's list. A key with an empty list works from any IP. Test and live keys have their own lists.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "`idempotency_key_reused`: Idempotency key was already used with a different request. Use a new Idempotency-Key for a different request, or resend exactly the same body.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "`validation_failed`: The request is not valid. Fix the fields listed in \"errors\" and send the request again.\n\n`method_unavailable`: This payment method is not available right now. Try another method or amount, or try again later. For a card_to_card deposit the answer also has suggested_amounts: up to 3 amounts, in the currency you sent, that could be paid right now (closest first; empty when none).\n\n`unknown_user_level`: There is no user level with this name. Send in customer.level the name of one of your user levels, as listed in your panel (Customers, Levels; upper or lower case does not matter), or leave customer.level out: the customer then gets the level set for them in the panel, or your default level. Levels are the same in test and live mode.\n\n`amount_outside_level_limits`: The amount is outside the limits of the customer's user level. Each user level may have a smallest and a largest deposit amount (in rials, set in your panel: Customers, Levels). Ask the customer for an amount inside those limits, or change the limits or the customer's level in the panel. The detail names the level and its limits.\n\n`amount_outside_method_limits`: The amount is outside your limits for this method. Each merchant has a smallest and a largest withdrawal amount, and a smallest and a largest deposit for each deposit method (in rials, set in your panel: Limits). Ask for an amount inside those limits, or split a larger withdrawal into several, or change the limits in the panel. The detail names the limits.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "`rate_limit_exceeded`: Too many requests. Wait for the time in the Retry-After header, then retry.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "`internal_error`: Internal error. Retry later. If it keeps happening, contact support with the request_id.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    }
                }
            }
        },
        "\/deposits\/{deposit}": {
            "get": {
                "operationId": "v1.deposits.show",
                "description": "Only deposits of the API key's merchant AND mode are found: a live key never finds a test deposit and a test\nkey never a live one; any other id answers `deposit_not_found`. To confirm a payment before you deliver an\norder, get the deposit with your live key.\n\nThe same object as in webhooks. When you compare it with a webhook you already processed, the higher\n`version` is the newer state. An expired or failed deposit can still become paid, so always credit the\norder on `deposit.paid`.",
                "summary": "Get a deposit",
                "tags": [
                    "Deposit"
                ],
                "parameters": [
                    {
                        "name": "deposit",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`Deposit`",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Deposit"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "`authentication_failed`: Authentication failed. Send a valid secret key in the Authorization header: \"Bearer sk_live_\u2026\" or \"Bearer sk_test_\u2026\".",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "`live_mode_disabled`: Live mode is not turned on for this merchant. Your live keys (sk_live_\u2026) work once live mode is turned on for your merchant account; ask us to turn it on when your integration is ready. Until then use a test key (sk_test_\u2026): test deposits never move real money.\n\n`ip_not_allowed`: This key may not be used from this IP address. The key has an IP allowlist (set per key in your panel: Developers, IP allowlist) and the call came from an address that is not on it; the detail names that address. Call from one of your listed servers, or add the address (or its range) to the key's list. A key with an empty list works from any IP. Test and live keys have their own lists.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "`deposit_not_found`: Deposit not found. Check the deposit id. You can only see deposits of your own merchant account.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "`rate_limit_exceeded`: Too many requests. Wait for the time in the Retry-After header, then retry.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "`internal_error`: Internal error. Retry later. If it keeps happening, contact support with the request_id.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    }
                }
            }
        },
        "\/deposits\/{deposit}\/simulate": {
            "post": {
                "operationId": "v1.deposits.simulate",
                "description": "Test keys only. Ends a pending TEST deposit the way a real payment would: `paid` (our fee, your test\nbalance, webhook `deposit.paid`), `failed` (`failure_code` `payment_failed`, webhook `deposit.failed`) or\n`expired` (`failure_code` `deposit_expired`, webhook `deposit.expired`); `version` goes up by 1. Answers the\ndeposit as it is now. The customer's payment page of a test deposit has the same three buttons, and takes the\ntest cards and test tracking numbers of the guide (Test data), which may end the deposit before this call does.\n\nA test deposit made without a method that is still `waiting_for_method`: `paid` and `failed` need `method`\n(the simulator picks it as the customer would, then ends the deposit); `expired` needs none.\n\nTest webhooks are signed with your test webhook secret, never the live one, and go to the `webhook_url` sent with\nthat test deposit: verify each webhook with the secret of its `mode`, or confirm with `GET \/v1\/deposits\/{id}`\nusing your live key, before you deliver an order.\n\nA live key answers `test_mode_only`; a deposit that already ended answers `deposit_not_open`. Sending the\nsame Idempotency-Key and outcome again returns the deposit with `Idempotent-Replayed: true`; the same key\nwith another outcome is refused.",
                "summary": "Simulate the end of a test deposit",
                "tags": [
                    "Deposit"
                ],
                "parameters": [
                    {
                        "name": "deposit",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "Idempotency-Key",
                        "in": "header",
                        "required": true,
                        "description": "Your unique key for this simulation, e.g. a UUID. 1 to 255 printable ASCII characters.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "simulate-10542-paid"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "$ref": "#\/components\/schemas\/DepositSimulation"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "id": {
                                            "type": "string",
                                            "examples": [
                                                "dep_01k6c3s0v1m2n3p4q5r6s7t8v9"
                                            ]
                                        },
                                        "object": {
                                            "type": "string",
                                            "const": "deposit"
                                        },
                                        "mode": {
                                            "description": "`test` or `live`: the mode of the key that created the deposit. A test deposit never moves real money:\nonly the simulator ends it. Test webhooks are signed with the test webhook secret, live ones with the\nlive secret (each goes to the `webhook_url` of its own deposit), so verify with the secret of `mode` before you deliver an order, or confirm with `GET \/v1\/deposits\/{id}` using your live key (a live key\nnever finds a test deposit).",
                                            "$ref": "#\/components\/schemas\/Mode"
                                        },
                                        "status": {
                                            "description": "waiting_for_method: the customer has not picked a method yet; pending: waiting for the customer's\npayment; paid: money received, credit the order; failed, expired: not paid, but a late payment can\nstill make them paid; cancelled: not paid, final (webhook `deposit.cancelled`); unknown: an operator is\nchecking a payment whose result is not clear (no webhook when it becomes unknown: the next one,\n`deposit.paid` or `deposit.failed`, says how it was settled).\nAn unpaid deposit becomes expired within about a minute after `expires_at` (webhook `deposit.expired`).\nA `card_to_card` deposit also expires earlier when the customer does nothing on the payment page for\nyour card idle minutes (10 by default), and is never expired while its card transfer is being made or\nchecked: it can stay pending past `expires_at`.",
                                            "$ref": "#\/components\/schemas\/DepositStatus"
                                        },
                                        "method": {
                                            "anyOf": [
                                                {
                                                    "description": "The method the customer pays with: the one you sent, or the one the customer picked on our payment page;\nnull while the status is waiting_for_method (the customer may also go back and pick another, until money\nmay move, so it can change while the deposit is pending and a method was not sent).\n| |\n|---|\n| `account_transfer` <br\/> Bank account transfer: the customer transfers to the merchant's bank account. |\n| `pol_transfer` <br\/> Pol transfer to the merchant's account (Sheba). |\n| `card_to_card` <br\/> Card-to-card transfer. |\n| `bank_gateway` <br\/> Iranian bank payment gateway. |",
                                                    "$ref": "#\/components\/schemas\/DepositMethod"
                                                },
                                                {
                                                    "type": "null"
                                                }
                                            ]
                                        },
                                        "amount": {
                                            "type": "integer",
                                            "description": "Amount in `currency`, as you sent it."
                                        },
                                        "currency": {
                                            "$ref": "#\/components\/schemas\/Currency"
                                        },
                                        "amount_rials": {
                                            "type": "integer",
                                            "description": "The amount in rials."
                                        },
                                        "fee_rials": {
                                            "type": [
                                                "integer",
                                                "null"
                                            ],
                                            "description": "Our fee in rials, set when the deposit is paid; null before."
                                        },
                                        "reference": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "Your own order id from the create request, or null.",
                                            "examples": [
                                                "order-10542"
                                            ]
                                        },
                                        "customer": {
                                            "type": "object",
                                            "description": "`id`: your own id for the customer. `level`: the name of the customer's user level used for this\ndeposit (a level set for the customer in your panel, else the `customer.level` you sent, else your\ndefault level); null only on deposits made before user levels existed.",
                                            "properties": {
                                                "id": {
                                                    "type": "string"
                                                },
                                                "level": {
                                                    "type": [
                                                        "string",
                                                        "null"
                                                    ]
                                                }
                                            },
                                            "required": [
                                                "id",
                                                "level"
                                            ]
                                        },
                                        "payer": {
                                            "description": "Who paid and from where, in full (never in a webhook): `card_number` is the card the customer paid from\n(a `card_to_card` deposit whose card form was sent; null otherwise), `account` the account number or Sheba\nthe customer typed on a bank transfer page (null otherwise), `bank` that account's bank (null when we do\nnot know it). Webhooks never carry this object: read it with `GET \/v1\/deposits\/{id}`.",
                                            "anyOf": [
                                                {
                                                    "type": "object",
                                                    "properties": {
                                                        "card_number": {
                                                            "type": [
                                                                "string",
                                                                "null"
                                                            ]
                                                        },
                                                        "account": {
                                                            "type": [
                                                                "string",
                                                                "null"
                                                            ]
                                                        },
                                                        "bank": {
                                                            "type": [
                                                                "string",
                                                                "null"
                                                            ]
                                                        }
                                                    },
                                                    "required": [
                                                        "card_number",
                                                        "account",
                                                        "bank"
                                                    ]
                                                },
                                                {
                                                    "type": "object"
                                                }
                                            ]
                                        },
                                        "redirect_url": {
                                            "type": "string"
                                        },
                                        "webhook_url": {
                                            "type": "string",
                                            "description": "Where this deposit's webhooks are sent: the `webhook_url` of the create request, fixed for the deposit\n(there is no general webhook URL). \"Send again\" uses it too. Each event is sent once unless you turn on\nAutomatic retries in your panel."
                                        },
                                        "allowed_methods": {
                                            "type": [
                                                "array",
                                                "null"
                                            ],
                                            "description": "The `allowed_methods` of the create request, in our order; null when it was not sent (the customer\ncould pick any method that works now, or you sent `method`).",
                                            "items": {
                                                "$ref": "#\/components\/schemas\/DepositMethod"
                                            }
                                        },
                                        "failure_code": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "Why the deposit was not paid, as a readable code from the error code list: `deposit_expired` when\nit expired, `payment_failed` when the payment did not go through, `gateway_unavailable` when no bank\ngateway could take a `bank_gateway` payment, `card_transfer_failed` when a `card_to_card` transfer\ncould not be made (no money moved), `method_unavailable` when no card transfer could start right now,\n`deposit_cancelled` when the customer cancelled the payment. Null while it is open, and null again once\nit is paid (also when an expired deposit is paid late).",
                                            "examples": [
                                                "deposit_expired"
                                            ]
                                        },
                                        "failure_message": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "A short English text for `failure_code`; null when `failure_code` is null.",
                                            "examples": [
                                                "The deposit expired before it was paid"
                                            ]
                                        },
                                        "version": {
                                            "type": "integer",
                                            "description": "Starts at 1 and increases by 1 on every status change. Ignore a webhook whose version is lower\nthan one you already processed for this deposit. An expired or failed deposit can still become\npaid, so always credit the order on deposit.paid.",
                                            "examples": [
                                                2
                                            ]
                                        },
                                        "created_at": {
                                            "type": "string"
                                        },
                                        "updated_at": {
                                            "type": "string",
                                            "description": "When anything on the deposit last changed."
                                        },
                                        "expires_at": {
                                            "type": "string",
                                            "description": "When the deposit expires if it is not paid by then. A `card_to_card` deposit may expire before it, when\nthe customer does nothing on the payment page for your card idle minutes (10 by default), and never\nexpires while its card transfer is being made or checked (it can stay pending past this time). For a\ndeposit made without `method` it is set again when the customer picks one: the picked method's own time,\nnever more than 2 hours after the deposit was made, so read it from `GET` or the webhook, not only from the\ncreate answer."
                                        },
                                        "paid_at": {
                                            "type": [
                                                "string",
                                                "null"
                                            ]
                                        }
                                    },
                                    "required": [
                                        "id",
                                        "object",
                                        "mode",
                                        "status",
                                        "method",
                                        "amount",
                                        "currency",
                                        "amount_rials",
                                        "fee_rials",
                                        "reference",
                                        "customer",
                                        "payer",
                                        "redirect_url",
                                        "webhook_url",
                                        "allowed_methods",
                                        "failure_code",
                                        "failure_message",
                                        "version",
                                        "created_at",
                                        "updated_at",
                                        "expires_at",
                                        "paid_at"
                                    ]
                                }
                            }
                        },
                        "headers": {
                            "Idempotent-Replayed": {
                                "description": "Present (\"true\") when this response is a replay of an earlier request with the same Idempotency-Key.",
                                "schema": {
                                    "type": "string"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "`authentication_failed`: Authentication failed. Send a valid secret key in the Authorization header: \"Bearer sk_live_\u2026\" or \"Bearer sk_test_\u2026\".",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "`test_mode_only`: This works only in test mode. Simulate only test deposits and test withdrawals, with a test key (sk_test_\u2026). A live deposit is paid only by the customer's real payment, a live withdrawal only by a real transfer.\n\n`live_mode_disabled`: Live mode is not turned on for this merchant. Your live keys (sk_live_\u2026) work once live mode is turned on for your merchant account; ask us to turn it on when your integration is ready. Until then use a test key (sk_test_\u2026): test deposits never move real money.\n\n`ip_not_allowed`: This key may not be used from this IP address. The key has an IP allowlist (set per key in your panel: Developers, IP allowlist) and the call came from an address that is not on it; the detail names that address. Call from one of your listed servers, or add the address (or its range) to the key's list. A key with an empty list works from any IP. Test and live keys have their own lists.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "`deposit_not_found`: Deposit not found. Check the deposit id. You can only see deposits of your own merchant account.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "`deposit_not_open`: The deposit is not open any more. The deposit is already paid, failed, expired or cancelled, so it cannot change any more, or its time ran out (expires_at passed), so it can only expire. Get it with GET \/v1\/deposits\/{id} to see how it ended; create a new deposit to try again.\n\n`idempotency_key_reused`: Idempotency key was already used with a different request. Use a new Idempotency-Key for a different request, or resend exactly the same body.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "`validation_failed`: The request is not valid. Fix the fields listed in \"errors\" and send the request again.\n\n`method_unavailable`: This payment method is not available right now. Try another method or amount, or try again later. For a card_to_card deposit the answer also has suggested_amounts: up to 3 amounts, in the currency you sent, that could be paid right now (closest first; empty when none).",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "`rate_limit_exceeded`: Too many requests. Wait for the time in the Retry-After header, then retry.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "`internal_error`: Internal error. Retry later. If it keeps happening, contact support with the request_id.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    }
                }
            }
        },
        "\/withdrawals": {
            "post": {
                "operationId": "v1.withdrawals.store",
                "description": "Pays your customer out to their own card and Sheba. A new withdrawal waits for your approval in your panel\n(`waiting_for_approval`), where your team picks how it is paid; with an automatic approval limit set in your\npanel (Limits), a withdrawal of at most that amount is approved at once (`open`, method `p2p`). You get the\nwebhook `withdrawal.paid` when all of it was paid, `withdrawal.cancelled` when it was cancelled (it may have been\npaid in part: `paid_amount_rials`).\n\nSending the same Idempotency-Key with the same body again returns the same withdrawal with the header\n`Idempotent-Replayed: true`; the same key with another body is refused. The amount must be inside your\nwithdrawal limits (Limits in your panel). The bank is read from the card number and the Sheba: do not send it.\n\n`webhook_url` is required: every webhook of this withdrawal goes to it, and only to it.\n\nWith one withdrawal per customer per day turned on (Limits), a second API withdrawal for the same customer within\n24 hours answers `customer_has_recent_withdrawal` with `next_allowed_at`; cancelled or failed ones and panel-made\nones do not count.\n\nThe key decides the mode: a test key makes a test withdrawal (`mode: test`), which never moves real money; end it\nwith `POST \/v1\/withdrawals\/{id}\/simulate`. Idempotency-Keys and customers are separate in each mode.\n\nA test key takes only the test cards and test Shebas of the guide (Test data), and no `destination.account_number`;\na live key refuses a test card or test Sheba (`validation_failed` on the field). With the paid or the failed test\nSheba the test withdrawal ends by itself, `paid` or `failed`, within about a minute; with the third test Sheba\nnothing ends it but the simulate call.",
                "summary": "Create a withdrawal",
                "tags": [
                    "Withdrawal"
                ],
                "parameters": [
                    {
                        "name": "Idempotency-Key",
                        "in": "header",
                        "required": true,
                        "description": "Your unique key for this withdrawal, e.g. your payout id or a UUID. 1 to 255 printable ASCII characters.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "payout-20931"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "$ref": "#\/components\/schemas\/NewWithdrawal"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "id": {
                                            "type": "string",
                                            "examples": [
                                                "wd_01k6c3s0v1m2n3p4q5r6s7t8v9"
                                            ]
                                        },
                                        "object": {
                                            "type": "string",
                                            "const": "withdrawal"
                                        },
                                        "mode": {
                                            "description": "`test` or `live`: the mode of the key that created the withdrawal. A test withdrawal never moves real\nmoney: only the simulator ends it. Test webhooks are signed with the test webhook secret, live ones with\nthe live secret (each goes to the `webhook_url` of its own withdrawal), so verify with the secret of `mode`\nbefore you act on one.",
                                            "$ref": "#\/components\/schemas\/Mode"
                                        },
                                        "status": {
                                            "description": "waiting_for_approval: you have not approved it yet in your panel; open: approved, waiting to be paid;\npaying: a bank transfer for it is on its way; on_hold: held in your panel; paid: all of it was paid\n(final); failed (test mode only) and cancelled: not paid, or only in part (see `paid_amount_rials`), final;\nunknown: we are checking whether the last transfer went through.",
                                            "$ref": "#\/components\/schemas\/WithdrawalStatus"
                                        },
                                        "method": {
                                            "anyOf": [
                                                {
                                                    "description": "How it is paid: `p2p` (card-to-card transfers into the customer's card, in one or more parts) or\n`paya` (one Paya bank transfer to the customer's Sheba); null while it waits for approval.\n| |\n|---|\n| `p2p` <br\/> Paid by card-to-card transfers into the customer's card, in one or more parts. |\n| `paya` <br\/> Paid by one Paya bank transfer to the customer's Sheba. |",
                                                    "$ref": "#\/components\/schemas\/WithdrawalMethod"
                                                },
                                                {
                                                    "type": "null"
                                                }
                                            ]
                                        },
                                        "amount": {
                                            "type": "integer",
                                            "description": "Amount in `currency`, as you sent it."
                                        },
                                        "currency": {
                                            "$ref": "#\/components\/schemas\/Currency"
                                        },
                                        "paid_amount_rials": {
                                            "type": "integer",
                                            "description": "What reached the customer so far, always in rials (a withdrawal can be paid in parts of any number of\nrials): 0 until a part is paid, the whole amount once the status is paid, and on a cancelled withdrawal\nwhat was paid before it was cancelled."
                                        },
                                        "reference": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "Your own order id from the create request, or null.",
                                            "examples": [
                                                "payout-20931"
                                            ]
                                        },
                                        "customer": {
                                            "type": "object",
                                            "description": "`id`: your own id for the customer. `level`: the name of the customer's user level used for this\nwithdrawal (a level set for the customer in your panel, else the `customer.level` you sent, else your\ndefault level).",
                                            "properties": {
                                                "id": {
                                                    "type": "string"
                                                },
                                                "level": {
                                                    "type": "string"
                                                }
                                            },
                                            "required": [
                                                "id",
                                                "level"
                                            ]
                                        },
                                        "destination": {
                                            "type": "object",
                                            "description": "Where the money goes: the last 4 digits of the card and of the Sheba, the holder's name, the bank (read\nfrom the Sheba, else from the card number; null when we do not know the bank) and, in this answer only,\nthe card number (`card_number`, 16 digits), the Sheba (`sheba`, `IR` + 24 digits) and the account number\nyou sent (`account_number`, null when you sent none). A webhook carries only the last 4 digits.",
                                            "properties": {
                                                "card_last4": {
                                                    "type": "string"
                                                },
                                                "sheba_last4": {
                                                    "type": "string"
                                                },
                                                "holder_name": {
                                                    "type": "string"
                                                },
                                                "bank": {
                                                    "type": [
                                                        "string",
                                                        "null"
                                                    ]
                                                },
                                                "card_number": {
                                                    "type": "string"
                                                },
                                                "sheba": {
                                                    "type": "string"
                                                },
                                                "account_number": {
                                                    "type": [
                                                        "string",
                                                        "null"
                                                    ]
                                                }
                                            },
                                            "required": [
                                                "card_last4",
                                                "sheba_last4",
                                                "holder_name",
                                                "bank"
                                            ]
                                        },
                                        "version": {
                                            "type": "integer",
                                            "description": "Starts at 1 and increases by 1 on every status change. Ignore a webhook whose version is lower than one\nyou already processed for this withdrawal.",
                                            "examples": [
                                                2
                                            ]
                                        },
                                        "failure_code": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "Why a test withdrawal failed (`payment_failed`), as a code from the error code list; null otherwise.",
                                            "examples": [
                                                "payment_failed"
                                            ]
                                        },
                                        "failure_message": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "A short English text for `failure_code`; null when `failure_code` is null."
                                        },
                                        "webhook_url": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "The URL this withdrawal's webhooks are sent to: the `webhook_url` you sent when you created it. Null for a\nwithdrawal typed in your panel, which sends no webhook. Each event is sent once unless you turn on\nAutomatic retries in your panel.",
                                            "examples": [
                                                "https:\/\/shop.example.com\/webhooks\/payments"
                                            ]
                                        },
                                        "created_at": {
                                            "type": "string"
                                        },
                                        "updated_at": {
                                            "type": "string",
                                            "description": "When anything on the withdrawal last changed."
                                        },
                                        "paid_at": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "When the last part was paid; null until it is paid."
                                        }
                                    },
                                    "required": [
                                        "id",
                                        "object",
                                        "mode",
                                        "status",
                                        "method",
                                        "amount",
                                        "currency",
                                        "paid_amount_rials",
                                        "reference",
                                        "customer",
                                        "destination",
                                        "version",
                                        "failure_code",
                                        "failure_message",
                                        "webhook_url",
                                        "created_at",
                                        "updated_at",
                                        "paid_at"
                                    ]
                                }
                            }
                        },
                        "headers": {
                            "Idempotent-Replayed": {
                                "description": "Present (\"true\") when this response is a replay of an earlier request with the same Idempotency-Key.",
                                "schema": {
                                    "type": "string"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "`authentication_failed`: Authentication failed. Send a valid secret key in the Authorization header: \"Bearer sk_live_\u2026\" or \"Bearer sk_test_\u2026\".",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "`customer_blocked`: This customer is blocked. The customer (customer.id) is blocked in your panel (Customers), so they cannot make new deposits or get new withdrawals. Unblock them in the panel if this was a mistake. Test and live customers are blocked separately.\n\n`customer_method_blocked`: This customer is blocked from this payment method. The customer (customer.id) is blocked from this method (method) in your panel (Customers), so they cannot make a deposit with it, or blocked from withdrawals, so they cannot get a new withdrawal. Offer the customer another method, or remove the block in the panel if this was a mistake. Test and live customers are blocked separately.\n\n`live_mode_disabled`: Live mode is not turned on for this merchant. Your live keys (sk_live_\u2026) work once live mode is turned on for your merchant account; ask us to turn it on when your integration is ready. Until then use a test key (sk_test_\u2026): test deposits never move real money.\n\n`ip_not_allowed`: This key may not be used from this IP address. The key has an IP allowlist (set per key in your panel: Developers, IP allowlist) and the call came from an address that is not on it; the detail names that address. Call from one of your listed servers, or add the address (or its range) to the key's list. A key with an empty list works from any IP. Test and live keys have their own lists.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "`idempotency_key_reused`: Idempotency key was already used with a different request. Use a new Idempotency-Key for a different request, or resend exactly the same body.\n\n`customer_has_recent_withdrawal`: This customer has a recent withdrawal. One withdrawal per customer per day is turned on for your account (your panel: Limits). Wait until next_allowed_at, or cancel the earlier withdrawal in your panel (Withdrawals) if it should not be paid; a cancelled or failed withdrawal no longer counts. Withdrawals typed in your panel never count.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "`validation_failed`: The request is not valid. Fix the fields listed in \"errors\" and send the request again.\n\n`unknown_user_level`: There is no user level with this name. Send in customer.level the name of one of your user levels, as listed in your panel (Customers, Levels; upper or lower case does not matter), or leave customer.level out: the customer then gets the level set for them in the panel, or your default level. Levels are the same in test and live mode.\n\n`amount_outside_method_limits`: The amount is outside your limits for this method. Each merchant has a smallest and a largest withdrawal amount, and a smallest and a largest deposit for each deposit method (in rials, set in your panel: Limits). Ask for an amount inside those limits, or split a larger withdrawal into several, or change the limits in the panel. The detail names the limits.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "`rate_limit_exceeded`: Too many requests. Wait for the time in the Retry-After header, then retry.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "`internal_error`: Internal error. Retry later. If it keeps happening, contact support with the request_id.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    }
                }
            }
        },
        "\/withdrawals\/{withdrawal}": {
            "get": {
                "operationId": "v1.withdrawals.show",
                "description": "Only withdrawals of the API key's merchant AND mode are found: a live key never finds a test withdrawal and a\ntest key never a live one; any other id answers `withdrawal_not_found`. The same object as in webhooks; the\nhigher `version` is the newer state.",
                "summary": "Get a withdrawal",
                "tags": [
                    "Withdrawal"
                ],
                "parameters": [
                    {
                        "name": "withdrawal",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "`Withdrawal`",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Withdrawal"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "`authentication_failed`: Authentication failed. Send a valid secret key in the Authorization header: \"Bearer sk_live_\u2026\" or \"Bearer sk_test_\u2026\".",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "`live_mode_disabled`: Live mode is not turned on for this merchant. Your live keys (sk_live_\u2026) work once live mode is turned on for your merchant account; ask us to turn it on when your integration is ready. Until then use a test key (sk_test_\u2026): test deposits never move real money.\n\n`ip_not_allowed`: This key may not be used from this IP address. The key has an IP allowlist (set per key in your panel: Developers, IP allowlist) and the call came from an address that is not on it; the detail names that address. Call from one of your listed servers, or add the address (or its range) to the key's list. A key with an empty list works from any IP. Test and live keys have their own lists.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "`withdrawal_not_found`: Withdrawal not found. Check the withdrawal id. You can only see withdrawals of your own merchant account, and only in the mode of your key: a test key never finds a live withdrawal, a live key never a test one.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "`rate_limit_exceeded`: Too many requests. Wait for the time in the Retry-After header, then retry.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "`internal_error`: Internal error. Retry later. If it keeps happening, contact support with the request_id.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    }
                }
            }
        },
        "\/withdrawals\/{withdrawal}\/simulate": {
            "post": {
                "operationId": "v1.withdrawals.simulate",
                "description": "Test keys only. Ends a TEST withdrawal the way a real one would end: `paid` (all of it paid: your test balance\ngoes down by what was left, webhook `withdrawal.paid`) or `failed` (`failure_code` `payment_failed`, webhook\n`withdrawal.failed`). A test withdrawal still waiting for approval is approved first (`version` goes up by 1 for\neach change). Answers the withdrawal as it is now.\n\nTest webhooks are signed with your test webhook secret, never the live one, and go to the `webhook_url` sent with\nthat test withdrawal: verify each webhook with the secret of its `mode`.\n\nA test withdrawal to the paid or the failed test Sheba (Test data in the guide) ends by itself within about a\nminute; after that this call answers `withdrawal_not_open`. Use the third test Sheba when you want to end it here.\n\nA live key answers `test_mode_only`; a withdrawal that already ended, or is on hold in your panel, answers\n`withdrawal_not_open`. Sending the same Idempotency-Key and outcome again returns the withdrawal with\n`Idempotent-Replayed: true`; the same key with another outcome is refused.",
                "summary": "Simulate the end of a test withdrawal",
                "tags": [
                    "Withdrawal"
                ],
                "parameters": [
                    {
                        "name": "withdrawal",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    },
                    {
                        "name": "Idempotency-Key",
                        "in": "header",
                        "required": true,
                        "description": "Your unique key for this simulation, e.g. a UUID. 1 to 255 printable ASCII characters.",
                        "schema": {
                            "type": "string"
                        },
                        "example": "simulate-20931-paid"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application\/json": {
                            "schema": {
                                "$ref": "#\/components\/schemas\/WithdrawalSimulation"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "",
                        "content": {
                            "application\/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "id": {
                                            "type": "string",
                                            "examples": [
                                                "wd_01k6c3s0v1m2n3p4q5r6s7t8v9"
                                            ]
                                        },
                                        "object": {
                                            "type": "string",
                                            "const": "withdrawal"
                                        },
                                        "mode": {
                                            "description": "`test` or `live`: the mode of the key that created the withdrawal. A test withdrawal never moves real\nmoney: only the simulator ends it. Test webhooks are signed with the test webhook secret, live ones with\nthe live secret (each goes to the `webhook_url` of its own withdrawal), so verify with the secret of `mode`\nbefore you act on one.",
                                            "$ref": "#\/components\/schemas\/Mode"
                                        },
                                        "status": {
                                            "description": "waiting_for_approval: you have not approved it yet in your panel; open: approved, waiting to be paid;\npaying: a bank transfer for it is on its way; on_hold: held in your panel; paid: all of it was paid\n(final); failed (test mode only) and cancelled: not paid, or only in part (see `paid_amount_rials`), final;\nunknown: we are checking whether the last transfer went through.",
                                            "$ref": "#\/components\/schemas\/WithdrawalStatus"
                                        },
                                        "method": {
                                            "anyOf": [
                                                {
                                                    "description": "How it is paid: `p2p` (card-to-card transfers into the customer's card, in one or more parts) or\n`paya` (one Paya bank transfer to the customer's Sheba); null while it waits for approval.\n| |\n|---|\n| `p2p` <br\/> Paid by card-to-card transfers into the customer's card, in one or more parts. |\n| `paya` <br\/> Paid by one Paya bank transfer to the customer's Sheba. |",
                                                    "$ref": "#\/components\/schemas\/WithdrawalMethod"
                                                },
                                                {
                                                    "type": "null"
                                                }
                                            ]
                                        },
                                        "amount": {
                                            "type": "integer",
                                            "description": "Amount in `currency`, as you sent it."
                                        },
                                        "currency": {
                                            "$ref": "#\/components\/schemas\/Currency"
                                        },
                                        "paid_amount_rials": {
                                            "type": "integer",
                                            "description": "What reached the customer so far, always in rials (a withdrawal can be paid in parts of any number of\nrials): 0 until a part is paid, the whole amount once the status is paid, and on a cancelled withdrawal\nwhat was paid before it was cancelled."
                                        },
                                        "reference": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "Your own order id from the create request, or null.",
                                            "examples": [
                                                "payout-20931"
                                            ]
                                        },
                                        "customer": {
                                            "type": "object",
                                            "description": "`id`: your own id for the customer. `level`: the name of the customer's user level used for this\nwithdrawal (a level set for the customer in your panel, else the `customer.level` you sent, else your\ndefault level).",
                                            "properties": {
                                                "id": {
                                                    "type": "string"
                                                },
                                                "level": {
                                                    "type": "string"
                                                }
                                            },
                                            "required": [
                                                "id",
                                                "level"
                                            ]
                                        },
                                        "destination": {
                                            "type": "object",
                                            "description": "Where the money goes: the last 4 digits of the card and of the Sheba, the holder's name, the bank (read\nfrom the Sheba, else from the card number; null when we do not know the bank) and, in this answer only,\nthe card number (`card_number`, 16 digits), the Sheba (`sheba`, `IR` + 24 digits) and the account number\nyou sent (`account_number`, null when you sent none). A webhook carries only the last 4 digits.",
                                            "properties": {
                                                "card_last4": {
                                                    "type": "string"
                                                },
                                                "sheba_last4": {
                                                    "type": "string"
                                                },
                                                "holder_name": {
                                                    "type": "string"
                                                },
                                                "bank": {
                                                    "type": [
                                                        "string",
                                                        "null"
                                                    ]
                                                },
                                                "card_number": {
                                                    "type": "string"
                                                },
                                                "sheba": {
                                                    "type": "string"
                                                },
                                                "account_number": {
                                                    "type": [
                                                        "string",
                                                        "null"
                                                    ]
                                                }
                                            },
                                            "required": [
                                                "card_last4",
                                                "sheba_last4",
                                                "holder_name",
                                                "bank"
                                            ]
                                        },
                                        "version": {
                                            "type": "integer",
                                            "description": "Starts at 1 and increases by 1 on every status change. Ignore a webhook whose version is lower than one\nyou already processed for this withdrawal.",
                                            "examples": [
                                                2
                                            ]
                                        },
                                        "failure_code": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "Why a test withdrawal failed (`payment_failed`), as a code from the error code list; null otherwise.",
                                            "examples": [
                                                "payment_failed"
                                            ]
                                        },
                                        "failure_message": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "A short English text for `failure_code`; null when `failure_code` is null."
                                        },
                                        "webhook_url": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "The URL this withdrawal's webhooks are sent to: the `webhook_url` you sent when you created it. Null for a\nwithdrawal typed in your panel, which sends no webhook. Each event is sent once unless you turn on\nAutomatic retries in your panel.",
                                            "examples": [
                                                "https:\/\/shop.example.com\/webhooks\/payments"
                                            ]
                                        },
                                        "created_at": {
                                            "type": "string"
                                        },
                                        "updated_at": {
                                            "type": "string",
                                            "description": "When anything on the withdrawal last changed."
                                        },
                                        "paid_at": {
                                            "type": [
                                                "string",
                                                "null"
                                            ],
                                            "description": "When the last part was paid; null until it is paid."
                                        }
                                    },
                                    "required": [
                                        "id",
                                        "object",
                                        "mode",
                                        "status",
                                        "method",
                                        "amount",
                                        "currency",
                                        "paid_amount_rials",
                                        "reference",
                                        "customer",
                                        "destination",
                                        "version",
                                        "failure_code",
                                        "failure_message",
                                        "webhook_url",
                                        "created_at",
                                        "updated_at",
                                        "paid_at"
                                    ]
                                }
                            }
                        },
                        "headers": {
                            "Idempotent-Replayed": {
                                "description": "Present (\"true\") when this response is a replay of an earlier request with the same Idempotency-Key.",
                                "schema": {
                                    "type": "string"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "`authentication_failed`: Authentication failed. Send a valid secret key in the Authorization header: \"Bearer sk_live_\u2026\" or \"Bearer sk_test_\u2026\".",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "403": {
                        "description": "`test_mode_only`: This works only in test mode. Simulate only test deposits and test withdrawals, with a test key (sk_test_\u2026). A live deposit is paid only by the customer's real payment, a live withdrawal only by a real transfer.\n\n`live_mode_disabled`: Live mode is not turned on for this merchant. Your live keys (sk_live_\u2026) work once live mode is turned on for your merchant account; ask us to turn it on when your integration is ready. Until then use a test key (sk_test_\u2026): test deposits never move real money.\n\n`ip_not_allowed`: This key may not be used from this IP address. The key has an IP allowlist (set per key in your panel: Developers, IP allowlist) and the call came from an address that is not on it; the detail names that address. Call from one of your listed servers, or add the address (or its range) to the key's list. A key with an empty list works from any IP. Test and live keys have their own lists.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "`withdrawal_not_found`: Withdrawal not found. Check the withdrawal id. You can only see withdrawals of your own merchant account, and only in the mode of your key: a test key never finds a live withdrawal, a live key never a test one.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "`withdrawal_not_open`: The withdrawal is not open. The withdrawal already ended (paid, failed or cancelled) and cannot change any more, or it is on hold in your panel (release the hold first). Get it with GET \/v1\/withdrawals\/{id} to see its status.\n\n`idempotency_key_reused`: Idempotency key was already used with a different request. Use a new Idempotency-Key for a different request, or resend exactly the same body.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "`validation_failed`: The request is not valid. Fix the fields listed in \"errors\" and send the request again.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "`rate_limit_exceeded`: Too many requests. Wait for the time in the Retry-After header, then retry.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "`internal_error`: Internal error. Retry later. If it keeps happening, contact support with the request_id.",
                        "content": {
                            "application\/problem+json": {
                                "schema": {
                                    "$ref": "#\/components\/schemas\/Problem"
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "secret_key": {
                "type": "http",
                "description": "Your secret key in the Authorization header: `Bearer sk_test_\u2026` (test mode: test deposits and withdrawals only, no real money) or `Bearer sk_live_\u2026` (live mode, once it is turned on for your account). The key decides the mode of the request, and a key only sees deposits and withdrawals of its own mode. A key may have an IP allowlist (set per key in your panel); a call from any other IP answers `ip_not_allowed`. Server-to-server only: never put it in a browser or an app.",
                "scheme": "bearer"
            }
        },
        "schemas": {
            "Currency": {
                "type": "string",
                "description": "Currencies a merchant may send. We always store amounts in IRR (rials) as integers. TOM and IRT are the same thing: toman, 1 toman = 10 rials.\n",
                "enum": [
                    "IRR",
                    "TOM",
                    "IRT"
                ],
                "title": "Currency"
            },
            "Deposit": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "examples": [
                            "dep_01k6c3s0v1m2n3p4q5r6s7t8v9"
                        ]
                    },
                    "object": {
                        "type": "string",
                        "const": "deposit"
                    },
                    "mode": {
                        "description": "`test` or `live`: the mode of the key that created the deposit. A test deposit never moves real money:\nonly the simulator ends it. Test webhooks are signed with the test webhook secret, live ones with the\nlive secret (each goes to the `webhook_url` of its own deposit), so verify with the secret of `mode` before you deliver an order, or confirm with `GET \/v1\/deposits\/{id}` using your live key (a live key\nnever finds a test deposit).",
                        "$ref": "#\/components\/schemas\/Mode"
                    },
                    "status": {
                        "description": "waiting_for_method: the customer has not picked a method yet; pending: waiting for the customer's\npayment; paid: money received, credit the order; failed, expired: not paid, but a late payment can\nstill make them paid; cancelled: not paid, final (webhook `deposit.cancelled`); unknown: an operator is\nchecking a payment whose result is not clear (no webhook when it becomes unknown: the next one,\n`deposit.paid` or `deposit.failed`, says how it was settled).\nAn unpaid deposit becomes expired within about a minute after `expires_at` (webhook `deposit.expired`).\nA `card_to_card` deposit also expires earlier when the customer does nothing on the payment page for\nyour card idle minutes (10 by default), and is never expired while its card transfer is being made or\nchecked: it can stay pending past `expires_at`.",
                        "$ref": "#\/components\/schemas\/DepositStatus"
                    },
                    "method": {
                        "anyOf": [
                            {
                                "description": "The method the customer pays with: the one you sent, or the one the customer picked on our payment page;\nnull while the status is waiting_for_method (the customer may also go back and pick another, until money\nmay move, so it can change while the deposit is pending and a method was not sent).\n| |\n|---|\n| `account_transfer` <br\/> Bank account transfer: the customer transfers to the merchant's bank account. |\n| `pol_transfer` <br\/> Pol transfer to the merchant's account (Sheba). |\n| `card_to_card` <br\/> Card-to-card transfer. |\n| `bank_gateway` <br\/> Iranian bank payment gateway. |",
                                "$ref": "#\/components\/schemas\/DepositMethod"
                            },
                            {
                                "type": "null"
                            }
                        ]
                    },
                    "amount": {
                        "type": "integer",
                        "description": "Amount in `currency`, as you sent it."
                    },
                    "currency": {
                        "$ref": "#\/components\/schemas\/Currency"
                    },
                    "amount_rials": {
                        "type": "integer",
                        "description": "The amount in rials."
                    },
                    "fee_rials": {
                        "type": [
                            "integer",
                            "null"
                        ],
                        "description": "Our fee in rials, set when the deposit is paid; null before."
                    },
                    "reference": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Your own order id from the create request, or null.",
                        "examples": [
                            "order-10542"
                        ]
                    },
                    "customer": {
                        "type": "object",
                        "description": "`id`: your own id for the customer. `level`: the name of the customer's user level used for this\ndeposit (a level set for the customer in your panel, else the `customer.level` you sent, else your\ndefault level); null only on deposits made before user levels existed.",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "level": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        },
                        "required": [
                            "id",
                            "level"
                        ]
                    },
                    "payer": {
                        "type": "object",
                        "description": "Who paid and from where, in full (never in a webhook): `card_number` is the card the customer paid from\n(a `card_to_card` deposit whose card form was sent; null otherwise), `account` the account number or Sheba\nthe customer typed on a bank transfer page (null otherwise), `bank` that account's bank (null when we do\nnot know it). Webhooks never carry this object: read it with `GET \/v1\/deposits\/{id}`.",
                        "properties": {
                            "card_number": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "account": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "bank": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        },
                        "required": [
                            "card_number",
                            "account",
                            "bank"
                        ]
                    },
                    "redirect_url": {
                        "type": "string"
                    },
                    "webhook_url": {
                        "type": "string",
                        "description": "Where this deposit's webhooks are sent: the `webhook_url` of the create request, fixed for the deposit\n(there is no general webhook URL). \"Send again\" uses it too. Each event is sent once unless you turn on\nAutomatic retries in your panel."
                    },
                    "allowed_methods": {
                        "type": [
                            "array",
                            "null"
                        ],
                        "description": "The `allowed_methods` of the create request, in our order; null when it was not sent (the customer\ncould pick any method that works now, or you sent `method`).",
                        "items": {
                            "$ref": "#\/components\/schemas\/DepositMethod"
                        }
                    },
                    "failure_code": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Why the deposit was not paid, as a readable code from the error code list: `deposit_expired` when\nit expired, `payment_failed` when the payment did not go through, `gateway_unavailable` when no bank\ngateway could take a `bank_gateway` payment, `card_transfer_failed` when a `card_to_card` transfer\ncould not be made (no money moved), `method_unavailable` when no card transfer could start right now,\n`deposit_cancelled` when the customer cancelled the payment. Null while it is open, and null again once\nit is paid (also when an expired deposit is paid late).",
                        "examples": [
                            "deposit_expired"
                        ]
                    },
                    "failure_message": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "A short English text for `failure_code`; null when `failure_code` is null.",
                        "examples": [
                            "The deposit expired before it was paid"
                        ]
                    },
                    "version": {
                        "type": "integer",
                        "description": "Starts at 1 and increases by 1 on every status change. Ignore a webhook whose version is lower\nthan one you already processed for this deposit. An expired or failed deposit can still become\npaid, so always credit the order on deposit.paid.",
                        "examples": [
                            2
                        ]
                    },
                    "created_at": {
                        "type": "string"
                    },
                    "updated_at": {
                        "type": "string",
                        "description": "When anything on the deposit last changed."
                    },
                    "expires_at": {
                        "type": "string",
                        "description": "When the deposit expires if it is not paid by then. A `card_to_card` deposit may expire before it, when\nthe customer does nothing on the payment page for your card idle minutes (10 by default), and never\nexpires while its card transfer is being made or checked (it can stay pending past this time). For a\ndeposit made without `method` it is set again when the customer picks one: the picked method's own time,\nnever more than 2 hours after the deposit was made, so read it from `GET` or the webhook, not only from the\ncreate answer."
                    },
                    "paid_at": {
                        "type": [
                            "string",
                            "null"
                        ]
                    }
                },
                "required": [
                    "id",
                    "object",
                    "mode",
                    "status",
                    "method",
                    "amount",
                    "currency",
                    "amount_rials",
                    "fee_rials",
                    "reference",
                    "customer",
                    "redirect_url",
                    "webhook_url",
                    "allowed_methods",
                    "failure_code",
                    "failure_message",
                    "version",
                    "created_at",
                    "updated_at",
                    "expires_at",
                    "paid_at"
                ],
                "title": "Deposit"
            },
            "DepositMethod": {
                "type": "string",
                "description": "How a deposit is paid.\n| |\n|---|\n| `account_transfer` <br\/> Bank account transfer: the customer transfers to the merchant's bank account. |\n| `pol_transfer` <br\/> Pol transfer to the merchant's account (Sheba). |\n| `card_to_card` <br\/> Card-to-card transfer. |\n| `bank_gateway` <br\/> Iranian bank payment gateway. |",
                "enum": [
                    "account_transfer",
                    "pol_transfer",
                    "card_to_card",
                    "bank_gateway"
                ],
                "title": "DepositMethod"
            },
            "DepositSimulation": {
                "type": "object",
                "description": "The simulation of a test deposit's end (test keys only), with the Idempotency-Key header.",
                "properties": {
                    "outcome": {
                        "description": "How the test deposit ends: paid (fee, test balance, deposit.paid), failed (failure_code payment_failed,\ndeposit.failed) or expired (failure_code deposit_expired, deposit.expired).\n\n| |\n|---|\n| `paid` <br\/> The customer paid: our fee, your test balance, webhook deposit.paid. |\n| `failed` <br\/> The payment did not go through: failure_code payment_failed, webhook deposit.failed. |\n| `expired` <br\/> The customer did not pay in time: failure_code deposit_expired, webhook deposit.expired. |",
                        "$ref": "#\/components\/schemas\/SimulationOutcome"
                    },
                    "method": {
                        "anyOf": [
                            {
                                "description": "For a test deposit still waiting for its method (made without `method`): `paid` and `failed` need it,\nand the simulator picks it as the customer would before it ends the deposit (use a method your test\nsettings allow). `expired` needs none. Sending it for a deposit that already has a method is refused.\n\n| |\n|---|\n| `account_transfer` <br\/> Bank account transfer: the customer transfers to the merchant's bank account. |\n| `pol_transfer` <br\/> Pol transfer to the merchant's account (Sheba). |\n| `card_to_card` <br\/> Card-to-card transfer. |\n| `bank_gateway` <br\/> Iranian bank payment gateway. |",
                                "$ref": "#\/components\/schemas\/DepositMethod"
                            },
                            {
                                "type": "null"
                            }
                        ]
                    }
                },
                "required": [
                    "outcome"
                ],
                "title": "DepositSimulation"
            },
            "DepositStatus": {
                "type": "string",
                "description": "Deposit statuses. paid never changes again; failed and expired become paid only when a payment made in time is confirmed late; a failed or cancelled card-to-card deposit can also become paid after its receipt was checked (the deposit.paid event then comes after deposit.failed or deposit.cancelled, with a higher version). unknown means the payment could not be confirmed yet: we check it by hand; it is never retried automatically.\n",
                "enum": [
                    "waiting_for_method",
                    "pending",
                    "paid",
                    "failed",
                    "expired",
                    "cancelled",
                    "unknown"
                ],
                "title": "DepositStatus"
            },
            "Mode": {
                "type": "string",
                "description": "Test or live: the mode of the API key (`sk_test_\u2026` or `sk_live_\u2026`). A test deposit never moves real money.\n",
                "enum": [
                    "test",
                    "live"
                ],
                "title": "Mode"
            },
            "NewDeposit": {
                "type": "object",
                "description": "A new deposit, with the Idempotency-Key header. Which methods are open is answered with its own error code\n(method_unavailable), not as a validation error.\n\nSend `method` and the customer goes straight to that method's page and cannot switch. Leave it out and the customer\npicks on our payment page, from the methods that work now for them and the amount (optionally narrowed by\n`allowed_methods`), and may go back and pick another until money may move.",
                "properties": {
                    "amount": {
                        "type": "integer",
                        "description": "Amount in \"currency\", a whole number greater than 0, e.g. 150000 (a string of digits such as \"150000\" is accepted too)."
                    },
                    "currency": {
                        "$ref": "#\/components\/schemas\/Currency"
                    },
                    "customer": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string",
                                "description": "The merchant's own id for its customer.",
                                "pattern": "^[^\\p{Cc}\\x{202A}-\\x{202E}\\x{2066}-\\x{2069}]+$",
                                "maxLength": 191
                            },
                            "level": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "description": "Optional: the name of one of your user levels (set in your panel: Customers, Levels), e.g. \"vip\";\nupper or lower case does not matter. Without it the customer gets the level set for them in your\npanel, or your default level (\"default\"); a level set for the customer in your panel always wins.\nA name you do not have answers unknown_user_level; an amount outside the level's limits\namount_outside_level_limits; a customer blocked in your panel customer_blocked.",
                                "maxLength": 64
                            }
                        },
                        "required": [
                            "id"
                        ]
                    },
                    "method": {
                        "anyOf": [
                            {
                                "description": "Optional: account_transfer (bank account transfer), pol_transfer (Pol transfer), card_to_card\n(card-to-card) or bank_gateway (Iranian bank payment gateway). With it the customer goes straight to\nthat method's payment page and cannot switch. Without it the deposit starts as waiting_for_method and\nthe customer picks on our payment page, from the methods that work now for them and the amount.\nA method you took off in your panel (Limits) or one no bank account can take now answers\nmethod_unavailable; an amount outside your limits for the method answers amount_outside_method_limits.\nWithout a method, method_unavailable also means no method works at all right now.\n\n| |\n|---|\n| `account_transfer` <br\/> Bank account transfer: the customer transfers to the merchant's bank account. |\n| `pol_transfer` <br\/> Pol transfer to the merchant's account (Sheba). |\n| `card_to_card` <br\/> Card-to-card transfer. |\n| `bank_gateway` <br\/> Iranian bank payment gateway. |",
                                "$ref": "#\/components\/schemas\/DepositMethod"
                            },
                            {
                                "type": "null"
                            }
                        ]
                    },
                    "allowed_methods": {
                        "type": [
                            "array",
                            "null"
                        ],
                        "description": "Optional, only without `method`: the methods you let the customer pick from, 1 to 4 different values.\nThe page still offers only the ones that work now. Used with `method` it is refused (validation_failed).",
                        "items": {
                            "$ref": "#\/components\/schemas\/DepositMethod"
                        },
                        "minItems": 1,
                        "maxItems": 4,
                        "uniqueItems": true
                    },
                    "redirect_url": {
                        "type": "string",
                        "format": "uri",
                        "description": "Where the customer's browser goes after the payment page. Never proof of payment. At most 2048 characters.",
                        "maxLength": 2048
                    },
                    "webhook_url": {
                        "type": "string",
                        "format": "uri",
                        "description": "Required: where this deposit's webhooks go: the only place we send them (there is no general URL), fixed\nwhen the deposit is made. Any public https URL on any host, for example one URL per order, at most 2048\ncharacters; \"Send again\" uses it too. Never localhost, an internal name or a private IP address, and no\nuser name or password in it; the host's addresses are checked again whenever a webhook is sent, and a\nwebhook to an internal address fails. Redirects are not followed. Each event is sent once: a try that is\nnot answered with a 2xx within 10 seconds fails, and \"Send again\" in your panel sends it once more; turn on\nAutomatic retries in your panel (off by default) to have us try 12 times over about 2 days instead. The\nsame event can still arrive more than once: de-duplicate by the Webhook-Id header.",
                        "maxLength": 2048
                    },
                    "reference": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Optional: your own order id, e.g. \"order-10542\". Returned on the deposit and in webhooks.\n1 to 64 printable ASCII characters. Spaces around it are removed; an empty value means none.\nNot unique: the Idempotency-Key is what prevents duplicates. Part of the request: the same\nIdempotency-Key with another reference is refused.",
                        "pattern": "^[\\x20-\\x7E]{1,64}$"
                    }
                },
                "required": [
                    "amount",
                    "currency",
                    "customer",
                    "redirect_url",
                    "webhook_url"
                ],
                "title": "NewDeposit"
            },
            "NewWithdrawal": {
                "type": "object",
                "description": "A new withdrawal, with the Idempotency-Key header. Card number and Sheba may use Persian or Arabic digits and\nspaces or dashes.",
                "properties": {
                    "amount": {
                        "type": "integer",
                        "description": "Amount in \"currency\", a whole number greater than 0, e.g. 25000000 (a string of digits such as \"25000000\"\nis accepted too). In rials it must be inside your withdrawal limits (set in your panel: Limits)."
                    },
                    "currency": {
                        "$ref": "#\/components\/schemas\/Currency"
                    },
                    "customer": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string",
                                "description": "The merchant's own id for its customer: the same customer as in your deposits.",
                                "pattern": "^[^\\p{Cc}\\x{202A}-\\x{202E}\\x{2066}-\\x{2069}]+$",
                                "maxLength": 191
                            },
                            "level": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "description": "Optional: the name of one of your user levels, as for deposits (upper or lower case does not matter).\nThe level's deposit limits do not apply to withdrawals.",
                                "maxLength": 64
                            }
                        },
                        "required": [
                            "id"
                        ]
                    },
                    "destination": {
                        "type": "object",
                        "description": "Where the money goes: the customer's own card and Sheba. The bank is read from them.",
                        "properties": {
                            "card_number": {
                                "type": "string",
                                "description": "The customer's 16-digit bank card number, e.g. \"0000000000000018\" (spaces or dashes and Persian digits\nare accepted). Its check digit must be right. With a test key only the test cards of the guide (Test\ndata) are accepted; with a live key a test card is refused."
                            },
                            "sheba": {
                                "type": "string",
                                "description": "The customer's Sheba: IR and 24 digits, e.g. \"IR650000000000000000000003\" (spaces and Persian digits are\naccepted). Its check digits must be right. With a test key only the test Shebas of the guide (Test data)\nare accepted; with a live key a test Sheba is refused."
                            },
                            "holder_name": {
                                "type": "string",
                                "description": "The name of the card and account holder, as the bank has it.",
                                "pattern": "^[^\\p{Cc}]+$",
                                "maxLength": 120
                            },
                            "account_number": {
                                "type": [
                                    "string",
                                    "null"
                                ],
                                "description": "Optional: the customer's bank account number (digits only; Persian digits accepted). Live keys only: a\ntest key refuses it (test data has no bank account numbers).",
                                "maxLength": 64
                            }
                        },
                        "required": [
                            "card_number",
                            "sheba",
                            "holder_name"
                        ]
                    },
                    "reference": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Optional: your own id for this withdrawal, e.g. \"payout-20931\". Returned on the withdrawal and in\nwebhooks. 1 to 64 printable ASCII characters. Not unique: the Idempotency-Key prevents duplicates.",
                        "pattern": "^[\\x20-\\x7E]{1,64}$"
                    },
                    "webhook_url": {
                        "type": "string",
                        "format": "uri",
                        "description": "Where this withdrawal's webhooks go: any public https URL (never localhost, an internal name or a private\nIP address; redirects are not followed), at most 2048 characters. It is kept on the withdrawal and never\nchanges: the only place its webhooks are sent. Each event is sent once: a try that is not answered with a\n2xx within 10 seconds fails, and \"Send again\" in your panel sends it once more; turn on Automatic retries in\nyour panel (off by default) to have us try 12 times over about 2 days instead. The same event can still\narrive more than once: de-duplicate by the Webhook-Id header.",
                        "examples": [
                            "https:\/\/shop.example.com\/webhooks\/payments"
                        ],
                        "maxLength": 2048
                    }
                },
                "required": [
                    "amount",
                    "currency",
                    "customer",
                    "destination",
                    "webhook_url"
                ],
                "title": "NewWithdrawal"
            },
            "Problem": {
                "type": "object",
                "properties": {
                    "type": {
                        "type": "string",
                        "format": "uri",
                        "description": "The page on the docs site that explains this code."
                    },
                    "status": {
                        "type": "integer",
                        "description": "The HTTP status code."
                    },
                    "code": {
                        "type": "string",
                        "description": "Readable error code. Codes are never renamed or removed within \/v1; branch on this, not on the texts.",
                        "enum": [
                            "bad_request",
                            "validation_failed",
                            "authentication_failed",
                            "permission_denied",
                            "not_found",
                            "method_not_allowed",
                            "idempotency_key_reused",
                            "method_unavailable",
                            "deposit_not_found",
                            "payload_too_large",
                            "rate_limit_exceeded",
                            "internal_error",
                            "service_unavailable",
                            "device_disabled",
                            "deposit_expired",
                            "live_mode_disabled",
                            "test_mode_only",
                            "deposit_not_open",
                            "payment_failed",
                            "unknown_user_level",
                            "amount_outside_level_limits",
                            "customer_blocked",
                            "customer_method_blocked",
                            "gateway_unavailable",
                            "ip_not_allowed",
                            "amount_outside_method_limits",
                            "withdrawal_not_found",
                            "withdrawal_not_open",
                            "card_transfer_failed",
                            "deposit_cancelled",
                            "customer_has_recent_withdrawal"
                        ]
                    },
                    "title": {
                        "type": "string",
                        "description": "Short English text for the code."
                    },
                    "detail": {
                        "type": "string",
                        "description": "English text about this occurrence."
                    },
                    "errors": {
                        "type": "object",
                        "description": "Only for validation_failed: the messages for each field that is not valid.",
                        "additionalProperties": {
                            "type": "array",
                            "items": {
                                "type": "string"
                            }
                        }
                    },
                    "suggested_amounts": {
                        "type": "array",
                        "description": "Only for method_unavailable of a card_to_card deposit: up to 3 amounts, in the currency of the request, that could be paid right now, closest to the asked amount first; empty when there are none.",
                        "items": {
                            "type": "integer"
                        }
                    },
                    "next_allowed_at": {
                        "type": "string",
                        "format": "date-time",
                        "description": "Only for customer_has_recent_withdrawal: when the next withdrawal for this customer is possible (UTC)."
                    },
                    "request_id": {
                        "type": "string",
                        "description": "Send it to support when you ask about this request."
                    }
                },
                "required": [
                    "type",
                    "status",
                    "code",
                    "title",
                    "detail",
                    "request_id"
                ],
                "title": "Problem"
            },
            "SimulationOutcome": {
                "type": "string",
                "description": "How the simulator ends a test deposit: the three endings a real payment can have, each with the same status, failure_code and webhook a live deposit gets.\n| |\n|---|\n| `paid` <br\/> The customer paid: our fee, your test balance, webhook deposit.paid. |\n| `failed` <br\/> The payment did not go through: failure_code payment_failed, webhook deposit.failed. |\n| `expired` <br\/> The customer did not pay in time: failure_code deposit_expired, webhook deposit.expired. |",
                "enum": [
                    "paid",
                    "failed",
                    "expired"
                ],
                "title": "SimulationOutcome"
            },
            "Withdrawal": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "examples": [
                            "wd_01k6c3s0v1m2n3p4q5r6s7t8v9"
                        ]
                    },
                    "object": {
                        "type": "string",
                        "const": "withdrawal"
                    },
                    "mode": {
                        "description": "`test` or `live`: the mode of the key that created the withdrawal. A test withdrawal never moves real\nmoney: only the simulator ends it. Test webhooks are signed with the test webhook secret, live ones with\nthe live secret (each goes to the `webhook_url` of its own withdrawal), so verify with the secret of `mode`\nbefore you act on one.",
                        "$ref": "#\/components\/schemas\/Mode"
                    },
                    "status": {
                        "description": "waiting_for_approval: you have not approved it yet in your panel; open: approved, waiting to be paid;\npaying: a bank transfer for it is on its way; on_hold: held in your panel; paid: all of it was paid\n(final); failed (test mode only) and cancelled: not paid, or only in part (see `paid_amount_rials`), final;\nunknown: we are checking whether the last transfer went through.",
                        "$ref": "#\/components\/schemas\/WithdrawalStatus"
                    },
                    "method": {
                        "anyOf": [
                            {
                                "description": "How it is paid: `p2p` (card-to-card transfers into the customer's card, in one or more parts) or\n`paya` (one Paya bank transfer to the customer's Sheba); null while it waits for approval.\n| |\n|---|\n| `p2p` <br\/> Paid by card-to-card transfers into the customer's card, in one or more parts. |\n| `paya` <br\/> Paid by one Paya bank transfer to the customer's Sheba. |",
                                "$ref": "#\/components\/schemas\/WithdrawalMethod"
                            },
                            {
                                "type": "null"
                            }
                        ]
                    },
                    "amount": {
                        "type": "integer",
                        "description": "Amount in `currency`, as you sent it."
                    },
                    "currency": {
                        "$ref": "#\/components\/schemas\/Currency"
                    },
                    "paid_amount_rials": {
                        "type": "integer",
                        "description": "What reached the customer so far, always in rials (a withdrawal can be paid in parts of any number of\nrials): 0 until a part is paid, the whole amount once the status is paid, and on a cancelled withdrawal\nwhat was paid before it was cancelled."
                    },
                    "reference": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Your own order id from the create request, or null.",
                        "examples": [
                            "payout-20931"
                        ]
                    },
                    "customer": {
                        "type": "object",
                        "description": "`id`: your own id for the customer. `level`: the name of the customer's user level used for this\nwithdrawal (a level set for the customer in your panel, else the `customer.level` you sent, else your\ndefault level).",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "level": {
                                "type": "string"
                            }
                        },
                        "required": [
                            "id",
                            "level"
                        ]
                    },
                    "destination": {
                        "type": "object",
                        "description": "Where the money goes: the last 4 digits of the card and of the Sheba, the holder's name, the bank (read\nfrom the Sheba, else from the card number; null when we do not know the bank) and, in this answer only,\nthe card number (`card_number`, 16 digits), the Sheba (`sheba`, `IR` + 24 digits) and the account number\nyou sent (`account_number`, null when you sent none). A webhook carries only the last 4 digits.",
                        "properties": {
                            "card_last4": {
                                "type": "string"
                            },
                            "sheba_last4": {
                                "type": "string"
                            },
                            "holder_name": {
                                "type": "string"
                            },
                            "bank": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            },
                            "card_number": {
                                "type": "string"
                            },
                            "sheba": {
                                "type": "string"
                            },
                            "account_number": {
                                "type": [
                                    "string",
                                    "null"
                                ]
                            }
                        },
                        "required": [
                            "card_last4",
                            "sheba_last4",
                            "holder_name",
                            "bank"
                        ]
                    },
                    "version": {
                        "type": "integer",
                        "description": "Starts at 1 and increases by 1 on every status change. Ignore a webhook whose version is lower than one\nyou already processed for this withdrawal.",
                        "examples": [
                            2
                        ]
                    },
                    "failure_code": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "Why a test withdrawal failed (`payment_failed`), as a code from the error code list; null otherwise.",
                        "examples": [
                            "payment_failed"
                        ]
                    },
                    "failure_message": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "A short English text for `failure_code`; null when `failure_code` is null."
                    },
                    "webhook_url": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "The URL this withdrawal's webhooks are sent to: the `webhook_url` you sent when you created it. Null for a\nwithdrawal typed in your panel, which sends no webhook. Each event is sent once unless you turn on\nAutomatic retries in your panel.",
                        "examples": [
                            "https:\/\/shop.example.com\/webhooks\/payments"
                        ]
                    },
                    "created_at": {
                        "type": "string"
                    },
                    "updated_at": {
                        "type": "string",
                        "description": "When anything on the withdrawal last changed."
                    },
                    "paid_at": {
                        "type": [
                            "string",
                            "null"
                        ],
                        "description": "When the last part was paid; null until it is paid."
                    }
                },
                "required": [
                    "id",
                    "object",
                    "mode",
                    "status",
                    "method",
                    "amount",
                    "currency",
                    "paid_amount_rials",
                    "reference",
                    "customer",
                    "destination",
                    "version",
                    "failure_code",
                    "failure_message",
                    "webhook_url",
                    "created_at",
                    "updated_at",
                    "paid_at"
                ],
                "title": "Withdrawal"
            },
            "WithdrawalMethod": {
                "type": "string",
                "description": "How a withdrawal is paid; null while it waits for approval.\n| |\n|---|\n| `p2p` <br\/> Paid by card-to-card transfers into the customer's card, in one or more parts. |\n| `paya` <br\/> Paid by one Paya bank transfer to the customer's Sheba. |",
                "enum": [
                    "p2p",
                    "paya"
                ],
                "title": "WithdrawalMethod"
            },
            "WithdrawalSimulation": {
                "type": "object",
                "description": "The simulation of a test withdrawal's end (test keys only), with the Idempotency-Key header.",
                "properties": {
                    "outcome": {
                        "description": "How the test withdrawal ends: paid (your test balance, withdrawal.paid) or failed (failure_code\npayment_failed, withdrawal.failed).\n\n| |\n|---|\n| `paid` <br\/> All of it was paid: your test balance goes down by what was left, webhook withdrawal.paid. |\n| `failed` <br\/> It could not be paid: failure_code payment_failed, webhook withdrawal.failed. |",
                        "$ref": "#\/components\/schemas\/WithdrawalSimulationOutcome"
                    }
                },
                "required": [
                    "outcome"
                ],
                "title": "WithdrawalSimulation"
            },
            "WithdrawalSimulationOutcome": {
                "type": "string",
                "description": "How the simulator ends a test withdrawal.\n| |\n|---|\n| `paid` <br\/> All of it was paid: your test balance goes down by what was left, webhook withdrawal.paid. |\n| `failed` <br\/> It could not be paid: failure_code payment_failed, webhook withdrawal.failed. |",
                "enum": [
                    "paid",
                    "failed"
                ],
                "title": "WithdrawalSimulationOutcome"
            },
            "WithdrawalStatus": {
                "type": "string",
                "description": "Withdrawal statuses. waiting_for_approval: you have not approved it yet in your panel; open: approved, waiting to be paid; paying: a bank transfer for it is on its way; on_hold: held in your panel, nothing is paid until it is released; paid: all of it was paid, final; failed (test mode only) and cancelled: not paid (or only partly, see `paid_amount`), final; unknown: we are checking whether the last transfer went through.\n",
                "enum": [
                    "waiting_for_approval",
                    "open",
                    "paying",
                    "on_hold",
                    "paid",
                    "failed",
                    "cancelled",
                    "unknown"
                ],
                "title": "WithdrawalStatus"
            }
        }
    }
}