Reading this in another language? Use your browser's built-in translate option. Button and field names stay in English on purpose, to match what you see in Keysender.
A transaction is a sale Keysender fulfils: it takes codes from a database, sends them to the buyer with your template, and spends one credit per dispatch. Your software creates one whenever it sells outside a connected channel, for example from your own store or a marketplace Keysender does not integrate, and Keysender handles delivery from there.
TL;DR
POST /transaction/addcustom records a sale and delivers a code from a database you choose.id immediately, and never retry a call that already returned 200.POST /transaction/add repeats an earlier eBay, PayPal Button, or Allegro transaction with the same details.Doing this by hand instead of by code? See manually adding a transaction for the same delivery from the panel.
Make sure you have:
POST /login and the base URL https://panel.keysender.com/api/v1.0.template_id of the one to use. Without any template the call is rejected.POST /transaction/addcustom with the buyer, the quantity, the database, and the sale details: curl -X POST "https://panel.keysender.com/api/v1.0/transaction/addcustom" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"payer": "buyer@example.com", "quantity": 1, "database_id": 123, "amount": 9.99, "currency": "EUR", "name": "Example Game (Steam)"}'
payer (the buyer's email), quantity (1 to 5,000), database_id, amount (up to two decimals), currency, and name (what the buyer sees). Optional: template_id, msgsubject, and msgtext to override the template for this sale. id, status, quantity, quantity_sent, amount, currency, keysender_buyer_email, and keysender_code_id. Delivery runs in the background right after the call, so quantity_sent can still be 0 in this first response. addcustom call creates a new transaction and delivers codes again, even if the body is identical. id against your own order before you retry anything, and never retry a call that already returned 200. POST /transaction/add with source_transaction_id, payer, quantity, and database_id to create a new transaction with the same details as an earlier one. The source must be an eBay, PayPal Button, or Allegro transaction; other sources are rejected with 422. GET /transaction/456/inventory with the transaction id. The response lists each delivered code as {"id", "value", "kind"}; for file codes, value is the file encoded in base64 and fileName is added. 429 means slow down and retry after a minute. The new transaction appears under Transactions in the panel with the buyer's email, the database's available count drops by the quantity, and the buyer receives the delivery email from the template. See Viewing specific order details for what that record looks like in the panel.
| Symptom | Cause | Action |
|---|---|---|
422 naming a field |
One of the six required fields is missing or malformed | amount accepts digits with up to two decimals; recheck the field named in the response |
422 about a template |
No default template is set | Set one in Templates, or pass template_id |
| The buyer received two emails | The call was sent twice | Use the returned id to make retries safe, and never retry a call that already returned 200 |
Nothing delivered and quantity_sent stays 0 |
The database has no available codes, or the account has no credits | Check both before retrying |
Submit a ticket with the transaction id and the buyer's email.
Keysender creates a paid transaction, reserves the requested quantity from the database, sends the codes to the payer with your template, and spends one credit per dispatch. Delivery runs in the background right after the call returns.
No. There is no deduplication key, so a repeated call creates a second transaction and delivers again. Store the returned id against your order before you retry anything, and check the panel's Transactions page after a timeout.
Send GET /transaction/<id>/inventory. Each delivered code is listed with its id, value, and kind; file codes come back base64-encoded with a fileName.