Overview
Iron requires email two-factor authentication (2FA) for sensitive actions. This checks that actions cannot be performed on behalf of a customer without their explicit approval. 2FA is required in the following cases:- Editing the destination address of an Autoramp (fiat or wallet).
- Registering a fiat address that needs authorization.
- Reusing an existing vIBAN or account number (for example, cancelling and re-creating an Autoramp that reuses the same vIBAN).
- Changing a customer’s email address.
AuthorizationRequired state. It stays there until the customer confirms the action.
How it works
Customer triggers a sensitive action
Your app calls an endpoint that requires 2FA, such as editing an Autoramp destination. The entity moves to the
AuthorizationRequired state and Iron emails the customer a 2FA code with a confirmation link.Customer confirms via link or code
If the customer clicks the confirmation link in the email, the action completes and no further work is needed. If they don’t, they can enter the code manually in your app.
Fetch the pending authentication code
Look up the pending authentication code by the entity’s ID to get the authentication code ID you need for submission.
Request
Request
Submit the code
Submit the code the customer entered against the authentication code ID from the previous step.
Request
Request
Get the pending authentication code
GET /api/authentication-codes/entity/{id}
Returns the pending authentication code for an entity in the AuthorizationRequired state. The {id} is the ID of the entity itself (the Autoramp, fiat address, or email change), not the authentication code.
Response
| Field | Type | Description |
|---|---|---|
id | UUID | The authentication code ID. Use it to submit the code. |
status | string | One of Pending, Expired, Confirmed, Rejected |
attempts | integer | Number of submission attempts so far |
entity_id | UUID | The entity this authentication relates to |
expires_at | timestamp | When the code expires |
If no pending code exists for the entity, this endpoint returns
404 Not Found. This happens when the code expired or was already confirmed.Submit an authentication code
PUT /api/authentication-codes/{id}
Submits the code the customer received by email. The {id} is the authentication code ID from the previous endpoint.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
code | integer | Yes | The 2FA code from the customer’s email |
Response
Returns the updated authentication code. Checkstatus to confirm the result:
Authentication code statuses
| Status | Description |
|---|---|
Pending | The code was sent and is waiting for confirmation. |
Confirmed | The customer confirmed the action. The entity leaves AuthorizationRequired. |
Expired | The code passed its expires_at time without confirmation. |
Rejected | The submitted code was wrong too many times. |
Sub-partner scoping
Both endpoints accept an optionalX-SUB-PARTNER-ID header. When provided, the authentication code lookup and submission are scoped to that sub-partner.
Common errors
| Error | Cause |
|---|---|
401 Unauthorized | Missing or invalid X-API-Key |
404 Not Found | No pending authentication code for this entity, or the authentication code ID doesn’t exist |
500 Internal Error | Returns { "message": "...", "trace_id": "..." }. Reference the trace_id when reporting issues. |
The endpoints
POST /api/autoramps/{autoramp_id}/retry-auth and POST /api/addresses/fiat/{id}/retry-auth are deprecated. Don’t build on them. If no pending code exists for an entity, re-trigger the underlying action instead.Sandbox testing
In sandbox, the static code123456 confirms any pending authentication. Submit it as an integer:

