Wrapp Partners API documentation
OVERVIEW
The Partners API opens a Wrapp.ai account for each of your users and gives you the credentials to work on it. It does not issue documents itself: invoices and other documents are issued with the Wrapp.ai invoicing API, logged in as the user with those credentials.
How the two fit together:
- Create the user with
POST /api/v1/external_login. -
Store the
wrapp_user_idandapi_keyfrom the user created webhook. Thewrapp_user_idis also in the response. -
Log in to the invoicing API as the
user with
wrapp_user_idandapi_key, then issue documents with the token it returns.
An AI-friendly Markdown version of this documentation, ideal for LLMs and coding agents, is available at
https://wrapp.ai/api/partnersonboarding.md
GETTING ACCESS
To use the Partners API, create your partner yourself: sign up free at wrapp.ai, open «Partner Portal» from the menu and press «Create partner». Your Partner API key appears straight away. For testing, do the same inside the test account on staging.wrapp.ai: see how to open it.
Include the API key in your request headers as:
X-PARTNER-API-KEY: <your_key_here>
https://wrapp.ai/api/v1/
X-PARTNER-API-KEY: xxxxxxxxxxxxxxxxxxxxxxxxxxx
CREATE / LOGIN USER
To create a new user or log in an existing one, make a POST request to:
https://wrapp.ai/api/v1/external_login
Wrapp.ai will respond with a login_url. Open it for the user: on that page they ask for a one-time sign-in email to their own address, so only the user can enter the account. The link itself signs nobody in, and it is the same for a user on every call, so you can store it. The emailed sign-in link works for one hour.
PARAMETERS
| Param Name | Required | Type | Description |
|---|---|---|---|
| yes | string | Email of the user that will be used to create their account in Wrapp.ai | |
| partner_user_id | yes | string | External unique identifier that will be used to identify the user in Wrapp.ai |
| phone | yes | string | Phone of the user that will be used to create their account in Wrapp.ai |
| webhook_endpoint | no | string |
Webhook endpoint that will return details on user creation. It is also kept up to
date on every call: if you send a different endpoint for a user that already exists,
it replaces the stored one and subsequent webhooks are delivered there.
Omit the field to keep the current endpoint unchanged; a new user created without it
gets the general webhook set in your Partner Portal, if you have one. Send it blank
("") to remove it, after which no webhooks are
delivered for that user. It must be a valid http or https URL: anything else is
rejected with 422.
|
| company_vat_no | no | string | VAT number (ΑΦΜ) of the company |
| company_name | no | string | Legal name of the company |
| company_city | no | string | City of the company headquarters |
| company_address | no | string | Street of the company headquarters |
| company_street_number | no | string | Street number of the company headquarters |
| company_postal_code | no | string | Postal code of the company headquarters |
| company_phone | no | string | Phone of the company |
| company_legal_representative_name | no | string | Full name of the legal representative |
| company_activity | no | string | Business activity of the company |
| company_accountant_name | no | string | Full name of the accountant |
| company_accountant_email | no | string | Email of the accountant |
| company_accountant_phone | no | string | Phone of the accountant |
All company_* parameters are optional. When any of them is
sent, the company of the user is prefilled with these details so they do not have to type them
again during onboarding.
RESPONSE FIELDS
| Name | Type | Description |
|---|---|---|
| login_url | string | The page where the user asks for a one-time sign-in email |
| string | The email the user logs in to Wrapp.ai with right now. It changes when the user changes it inside Wrapp.ai. | |
| wrapp_user_id | string | Id of the user in Wrapp.ai, the same one the user created webhook sends. It never changes. |
To issue documents for this user,
log in to the invoicing API with
wrapp_user_id and the
user's api_key: the id does not change when the user changes their email.
If you log in with email instead, keep the
email returned here on file: an email that is no longer the user's login is
refused with "Not valid user".
curl -L 'https://wrapp.ai/api/v1/external_login' \
-H 'X-PARTNER-API-KEY: XXXXXXXXXXXXXXXXXXXXXXXX' \
-H 'Content-Type: application/json' \
-d '{
"email": "[email protected]",
"partner_user_id": "abc123",
"phone": "1234567890",
"webhook_endpoint": "https://yoursite.com/webhook",
"company_vat_no": "123456789",
"company_name": "Example Company",
"company_city": "Athens",
"company_address": "Ermou",
"company_street_number": "10",
"company_postal_code": "10563",
"company_phone": "2101234567",
"company_legal_representative_name": "Georgios Papadopoulos",
"company_activity": "IT services",
"company_accountant_name": "Maria Georgiou",
"company_accountant_email": "[email protected]",
"company_accountant_phone": "2109876543"
}'
{
"login_url": "https://wrapp.ai/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"email": "[email protected]",
"wrapp_user_id": "xxxxx-xxxxx-xxxxx-xxxxx"
}
WEBHOOK · USER CREATED
If the user was created, Wrapp.ai will send the following payload to the provided
webhook_endpoint.
If the first delivery attempt is unsuccessful, up to 4 additional attempts will be made.
It is sent only once, when the user is created: changing the
webhook_endpoint later redirects subsequent webhooks to the
new endpoint but does not resend this payload, so store the
api_key and the wrapp_user_id
you receive here. Use the two together to
log in to the invoicing API
on the user's behalf: the
wrapp_user_id stays the same if the user changes their email.
HEADER PARAMETERS
| Field | Description |
|---|---|
| Content-Type | application/json |
| Event-Type | tenant-details |
| X-Webhook-Secret |
HMAC-SHA256 hex digest of the raw request body, computed with your
X-PARTNER-API-KEY as the key. Optionally recompute it, e.g.
OpenSSL::HMAC.hexdigest('sha256', partner_api_key, raw_body),
and compare to verify the request originated from Wrapp.
|
FIELDS
| Param Name | Description |
|---|---|
| wrapp_user_id | Id of the user in Wrapp. It never changes, so log in with it rather than the email |
| partner_user_id | Id of the user in partner (the id provided in the initial call) |
| api_key | API key of the user, used for further API actions on their behalf |
{
"wrapp_user_id": "xxxxx-xxxxx-xxxxx-xxxxx",
"partner_user_id": "xxxxxxxxxx",
"api_key": "xxxxxxxxxxxxxxxxxxxxx"
}
CHECK USER
This endpoint shows if the user exists, whether they have an active subscription and whether they issue through Wrapp.ai as provider.
Make a POST request to:
https://wrapp.ai/api/v1/embedded_check_user
PARAMETERS
| Param Name | Required | Type | Description |
|---|---|---|---|
| partner_user_id | yes | string | Unique identifier that has been used to identify the user in Wrapp.ai |
RESPONSE FIELDS
| Name | Type | Description |
|---|---|---|
| user | string | User's email |
| active_subscription | boolean | True while the user has a subscription, including while a payment is unpaid: read billing.status for that |
| wrapp_provider_enabled | boolean | Whether the user issues invoices through Wrapp.ai as a certified provider |
| billing | object | Whether the Wrapp subscription is paid up. Every key below is always present, null when it does not apply. |
| billing.status | string | active paid up · overdue a payment is unpaid, issuing still works · cancelled paid up, ends on access_until · ended the subscription ended, the API refuses issuing · none never subscribed. |
| billing.overdue_since | string | YYYY-MM-DD. When the payment first failed. |
| billing.reason | string | authentication_required (the bank asked for 3D Secure), card_declined, insufficient_funds or expired_card. reason_title says it in words, in Greek unless the request sends Accept-Language: en. |
| billing.amount_due | decimal | What is owed, VAT included, in billing.currency. |
| billing.access_until | string | YYYY-MM-DD. The day the subscription is cancelled if still unpaid (known for 3D Secure), or the last paid day of a cancelled one. |
| billing.next_retry_at | string | YYYY-MM-DD. For a declined card, when the card is charged again automatically. |
| billing.ended_on | string | YYYY-MM-DD. When an ended subscription ended. |
| billing.pay_url | string | For overdue and ended: a link to give the user. It never expires and needs no login: it opens the payment while one is unpaid, and renewing once the subscription has ended. |
curl -L 'https://wrapp.ai/api/v1/embedded_check_user' \
-H 'X-PARTNER-API-KEY: XXXXXXXXXXXXXXXXXXX' \
-H 'Content-Type: application/json' \
-d '{"partner_user_id": "abc123"}'
{
"user": "[email protected]",
"active_subscription": true,
"wrapp_provider_enabled": true,
"billing": {
"status": "overdue",
"overdue_since": "2026-10-23",
"reason": "authentication_required",
"reason_title": "The bank asked to confirm the payment (3D Secure)",
"amount_due": 209.56,
"currency": "EUR",
"access_until": "2026-10-28",
"next_retry_at": null,
"ended_on": null,
"pay_url": "https://wrapp.ai/el/pay/xxxxxxxx"
}
}
Frequently asked questions
What is the Wrapp Partners API?
It is Wrapp's multi-tenant onboarding API: you create and manage Wrapp accounts (a subaccount per VAT number) for your end customers programmatically, so your app activates them for myDATA invoice issuance with no manual steps.
How do I create a Wrapp account for each of my customers via API?
Call POST /api/v1/external_login with email, partner_user_id and phone. Wrapp returns a login_url you open for the user: there they ask for a one-time sign-in email, so only they can enter the account. Once the account is created, Wrapp sends a webhook with the tenant's wrapp_user_id and api_key, which you use to issue documents on their behalf.
How do I get a Partner API key (X-PARTNER-API-KEY)?
You create it yourself, in a minute: sign up free at wrapp.ai, open «Partner Portal» from the menu and press «Create partner». Your Partner API key appears straight away. For testing, do the same inside the test account on staging.wrapp.ai (see how to open it): the partner there is a test one, with its own key.
How do I check whether a customer already has an account or an active subscription?
With POST /api/v1/embedded_check_user and the partner_user_id: the response returns the user's email and whether they have an active subscription (active_subscription).
What is the difference between the Partner key and a tenant's API key?
The X-PARTNER-API-KEY is only for onboarding: creating and checking users via the Partners API. Each tenant gets its own api_key, used to log in to the Invoice Issue API and issue its documents.
Who signs the contract with and bills the end customer?
Wrapp does: the end user digitally accepts the contract and pays for their subscription during onboarding. Your app remains the front-end; you do not handle billing or contracts.