HHeros Developers

Version 1.0.0

Heros REMIT AUTHORITY RAIL

Statutory remittance to Nigerian authorities, with proof of every payment.

Base URLhttps://sandbox.droomwork.io
AuthenticationDroomwork-Api-Key: dw_test_… or Authorization: Bearer dw_test_…
Events it sends8 webhooks →
Signed in: requests you run on this page use a key made for your account. Your keys →

REMIT files what your payroll says is owed with each authority and keeps the receipt for you.

What you should know before you start

You don't need RUN to use this. Send instruction sets from Heros payroll or from your own, by API or by file. The shape is the same either way, and so is everything that follows.

Intake is two steps. You submit, we validate and return a report, and nothing is committed until you accept. A discrepancy blocks acceptance until you resolve it or override it with a reason code. A figure filed wrongly is one you have to unwind with an authority.

One approval, many legs. A remittance executes one leg per authority, and each leg runs on its own. One authority being down never blocks the others, so a Federal Inland Revenue Service outage does not delay your pension filings.

A leg is complete when its receipt is vaulted. A receipt whose parsed amount, period or authority disagrees with the leg is quarantined, not accepted.

Every authority presents the same contract. Some file by direct API, some by portal automation, some by assisted manual filing. The request, the states, the webhooks and the evidence class are identical across all three. Tier is something you can read, never something you code against.

Getting started

Get a sandbox key from the developer portal. Submit an instruction set. Accept it. Create a remittance from it, approve it, then execute it.

Every operation below has two samples: Direct HTTP, with nothing but your language's own client, and Client library, with ours. Same request, same answer; the switch above each sample picks one and remembers it. Which should I use?

GET/v1/remittance/instruction_sets#

Check what you submitted and where it stands

remittance.instruction_sets.list

This is where you look up the months you have already submitted. Every record on the page is a whole set, its state and its validation report included, so one call fills a submissions screen without a read for each row.

You get a page of sets, each with the month it covers, the state it is in, the figures it holds and the report of every line that was flagged.

Take an id from the page and carry it as instruction_set_id, to GET /v1/remittance/instruction_sets/{instruction_set_id}/totals for what the month comes to, or to POST /v1/remittance/instruction_sets/{instruction_set_id}/accept while the set is still waiting on your decision.

Query parameters

limit integer optional

How many records to return on one page, from 1 to 100, and 25 if you leave it out. When has_more is true, pass the last record's id as starting_after to get the next page.

starting_after string optional

The id of the last record on the previous page of this same list. Leave it out to get the first page; when a page comes back with has_more true, send its last record's id here to get the page after it.

status string optional

Return only sets in this state: received on submission, validating while every line is checked, pending_acceptance once the report is back, accepted or rejected once you decide. Leave it out to get every state.

receivedvalidatingpending_acceptanceacceptedrejected
period string optional

Return only sets for this month, as YYYY-MM, such as 2026-09. Leave it out to get every period.

Returns

A page of instruction sets, each with created_at where there is one, to order your own rows by.

object always "list" required

Always list. Tells you which kind of record you are looking at, so one handler can read any response.

data array of IngestedInstructionSet required

The records on this page, in the order the list promises. Empty when nothing matched.

13 fields of IngestedInstructionSet
id string required

The set's identifier, starting remit_authority_rail_instruction_, as listed at GET /v1/remittance/instruction_sets. It never changes; pass it as instruction_set_id to retrieve, accept, reject or remit the set.

object always "ingested_instruction_set" required

Always ingested_instruction_set. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

status string required

Nothing is committed until accepted.

receivedvalidatingpending_acceptanceacceptedrejected
source string required

Where the set came from. Heros payroll or your own, by API or by file. Everything downstream behaves identically whichever it was.

runexternal_apiexternal_file
period string required

The month the set covers, as YYYY-MM, such as 2026-09. Filter the list by it with the period query.

run_id string · nullable optional

The Heros payroll run the set came from, by its id from POST /v1/payroll/runs or GET /v1/payroll/runs, starting run_enterprise_. Present when source is run; null when the set came from your own payroll.

instructions InstructionSet optional

What is owed to whom for one run. This shape is owned jointly by RUN and REMIT. RUN row 19 emits it and REMIT row 1 ingests it, from RUN and from external payroll alike. It lives here rather than in either module document so the two cannot drift, which is the failure that would otherwise surface at M3 with RUN already accepted and paid. Totals reconcile to run totals to the kobo, because they sum payslip lines rather than recompute from an aggregate. This is the object REMIT ingests.

11 fields of InstructionSet
id string required

The instruction set's identifier, which never changes: read it at GET /v1/payroll/runs/{run_id}/instruction_set when Heros ran the payroll, and send the set on unchanged to POST /v1/remittance/instruction_sets. Quote it when you ask about the set.

object always "instruction_set" required

Always instruction_set. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

run_id string required

The payroll run this set is owed for, by its id from POST /v1/payroll/runs, which starts with run_enterprise_. The set's totals reconcile to that run's totals to the kobo.

period string optional

The pay period the amounts are owed for, as year and month, for example 2026-09.

paye array of object required

Grouped by the State IRS of the employee's residence, not the employer's location.

5 fields
authority_id string required

The State Internal Revenue Service this PAYE is owed to, by its id from GET /v1/remittance/authorities, which starts with remit_authority_rail_obligation_. Use it wherever a call names the authority.

jurisdiction string required

The State Internal Revenue Service this line is grouped under, named in full, for example Rivers State Internal Revenue Service. Read it to label the line; authority_id names the authority in a call.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

payee_count integer optional

How many employees this line's PAYE covers. Optional; when it is present, check it against your own headcount for that state.

reconciliation_reference string required

The reference that identifies this line when you reconcile it, for example paye-2026-09-rivers. Keep it with your own records so you can trace the line later.

pension array of object required

Grouped by administrator and retirement savings account number.

6 fields
administrator_id string required

The Pension Fund Administrator these contributions are owed to, by its id from GET /v1/remittance/authorities with kind=pension_administrator, which starts with remit_authority_rail_obligation_. Use it wherever a call names the administrator.

administrator_name string optional

The administrator's name in full, so you can label the line without a second call. Optional; administrator_id is what names the administrator in a call.

employee_amount Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

employer_amount Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

reconciliation_reference string required

The reference that identifies this line when you reconcile it. Keep it with your own records so you can trace the line later.

levies array of object required

NHF, NSITF, ITF and NHIA totals, each with a reconciliation reference.

3 fields
code string required

Which levy this line is for: nhf the National Housing Fund, nsitf the Nigeria Social Insurance Trust Fund, itf the Industrial Training Fund, nhia the National Health Insurance Authority. One line per levy.

nhfnsitfitfnhia
amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

reconciliation_reference string required

The reference that identifies this levy line when you reconcile it. Keep it with your own records so you can trace the line later.

totals object required

The set's grand total, which its lines sum to. From a Heros run it reconciles to the run's totals to the kobo.

1 field
total Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

created_at string · date-time optional

When the record was created, as an RFC 3339 timestamp in UTC.

validation_report ValidationReport required

The result of checking a submission before anything is committed. Names every failing entry rather than stopping at the first, so one submission tells you everything to fix. The same shape wherever the platform ingests, validates and reports, which is every bulk intake in every module.

4 fields of ValidationReport
entry_count integer · minimum 0 required

How many entries the submission held: every row in the file or line in the instruction set, whether it passed or not.

error_count integer · minimum 0 required

How many entries failed with an error. Each is named in entries with its position and why, so one submission tells you everything to fix.

warning_count integer · minimum 0 required

How many entries passed with a warning, each named in entries. A warning does not fail the entry; it points at something to confirm before you go ahead.

entries array of object optional

One item per error or warning found, with the row or line it sits on, its severity, a code and what was wrong. Empty or absent when every entry passed clean.

4 fields
index integer · minimum 1 required

The row in a file, or the line in an instruction set.

severity string required

error means the entry failed and must be fixed. warning means it passed, but points at something you should confirm before you go ahead.

errorwarning
code string required

Why the entry was flagged, as a code you can branch on. detail says the same in words and may change; the code does not.

detail string required

What was wrong with the entry, in plain words. Show it beside the row; it may change, so branch on code.

jurisdiction_pack object optional

The jurisdiction pack the set is pinned to, by identifier and version. Every line was recomputed against it, so its rules are the ones the validation report reflects.

2 fields
pack_id string optional

Which jurisdiction pack the set is pinned to, such as ng-paye. We publish the packs and you never send this; with version, it names exactly which rules every line was checked against, and it stays with the set so you can show which rules applied.

version string optional

The pack version the set was checked against, such as 2026.08.1. It's pinned, so a later pack release doesn't change what this set was judged by.

accepted_by string · nullable optional

Who accepted the set: the actor that called accept. null until the set is accepted.

created_at string · date-time optional

When the record was created, as an RFC 3339 timestamp in UTC.

has_more boolean required

true when there are more records after this page. Pass the last record's id as starting_after to get the next page.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
# query parameters: limit (optional), starting_after (optional), status (optional), period (optional)
curl -X GET "https://sandbox.droomwork.io/v1/remittance/instruction_sets?limit=25&status=received&period=2026-09" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

// query parameters: limit (optional), starting_after (optional), status (optional), period (optional)
const result = await api.remittanceInstructionSetsList({ limit: 25, status: 'received', period: '2026-09' });
// query parameters: limit (optional), starting_after (optional), status (optional), period (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/instruction_sets?limit=25&status=received&period=2026-09', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

# query parameters: limit (optional), starting_after (optional), status (optional), period (optional)
result = api.remittance_instruction_sets_list(limit=25, status='received', period='2026-09')
import os

import requests

# query parameters: limit (optional), starting_after (optional), status (optional), period (optional)
response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/instruction_sets?limit=25&status=received&period=2026-09',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

# query parameters: limit (optional), starting_after (optional), status (optional), period (optional)
$result = $api->remittanceInstructionSetsList(limit: 25, status: 'received', period: '2026-09');
<?php
// query parameters: limit (optional), starting_after (optional), status (optional), period (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/instruction_sets?limit=25&status=received&period=2026-09');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;
import com.useheros.sdk.model.*;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

// query parameters: limit (optional), starting_after (optional), status (optional), period (optional)
var result = api.remittanceInstructionSetsList(25, null, RemitInstructionSetStatus.fromValue("received"), "2026-09");
// query parameters: limit (optional), starting_after (optional), status (optional), period (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/instruction_sets?limit=25&status=received&period=2026-09"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

// query parameters: limit (optional), starting_after (optional), status (optional), period (optional)
var result = api.RemittanceInstructionSetsList(limit: 25, status: RemitInstructionSetStatus.Received, period: "2026-09");
// query parameters: limit (optional), starting_after (optional), status (optional), period (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/instruction_sets?limit=25&status=received&period=2026-09");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

// query parameters: limit (optional), starting_after (optional), status (optional), period (optional)
result, _, err := client.REMITAPI.RemittanceInstructionSetsList(ctx).Limit(25).Status(heros.RemitInstructionSetStatus("received")).Period("2026-09").Execute()
// query parameters: limit (optional), starting_after (optional), status (optional), period (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/instruction_sets?limit=25&status=received&period=2026-09", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "object": "list",
  "data": [
    {
      "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "object": "ingested_instruction_set",
      "livemode": false,
      "mocked": true,
      "status": "received",
      "source": "run",
      "period": "2026-09",
      "validation_report": {
        "entry_count": 0,
        "error_count": 0,
        "warning_count": 0,
        "entries": [
          {
            "index": 1,
            "severity": "error",
            "code": "invalid_money_amount",
            "detail": "The payee has no verified destination, so this line cannot be paid."
          }
        ]
      },
      "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "instructions": {
        "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
        "object": "instruction_set",
        "livemode": false,
        "mocked": true,
        "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
        "paye": [
          {
            "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
            "jurisdiction": "Rivers State Internal Revenue Service",
            "amount": {
              "amount": 7500000,
              "currency": "NGN"
            },
            "reconciliation_reference": "paye-2026-09-rivers",
            "payee_count": 1
          }
        ],
        "pension": [
          {
            "administrator_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
            "amount": {
              "amount": 7500000,
              "currency": "NGN"
            },
            "reconciliation_reference": "paye-2026-09-rivers",
            "administrator_name": "example",
            "employee_amount": {
              "amount": 4200000,
              "currency": "NGN"
            },
            "employer_amount": {
              "amount": 5400000,
              "currency": "NGN"
            }
          }
        ],
        "levies": [
          {
            "code": "nhf",
            "amount": {
              "amount": 7500000,
              "currency": "NGN"
            },
            "reconciliation_reference": "paye-2026-09-rivers"
          }
        ],
        "totals": {
          "total": {
            "amount": 57900000,
            "currency": "NGN"
          }
        },
        "period": "2026-09",
        "created_at": "2026-09-01T09:00:00Z"
      },
      "jurisdiction_pack": {
        "pack_id": "ng-paye",
        "version": "2026.08.1"
      },
      "accepted_by": "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "created_at": "2026-09-01T09:00:00Z"
    }
  ],
  "has_more": true
}
POST/v1/remittance/instruction_sets#

Submit the month's figures for checking

remittance.instruction_sets.create

Filing a month starts here. Every line is recomputed against the jurisdiction pack the set is pinned to, and the report that comes back names each line it flagged, so your product can put a whole month's problems in front of somebody at once.

You send the period and the figures: PAYE grouped by the employee's State IRS, pension by administrator, levies by code. You get back the stored set, with an id starting remit_authority_rail_instruction_ and its validation report.

Nothing has to exist first, including a Heros payroll run.

The field to get right is run_id. Send it when these figures came from a Heros payroll run, and leave it out when they came from your own system.

Carry the id forward as instruction_set_id. Nothing is committed until you accept the set at POST /v1/remittance/instruction_sets/{instruction_set_id}/accept.

Headers

Idempotency-Key string required

A key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.

Body

period string required

The month the figures cover, as YYYY-MM, such as 2026-09. What you owe for it is recorded against this period once you accept.

run_id string optional

The Heros payroll run these figures come from, by its id from POST /v1/payroll/runs or GET /v1/payroll/runs, starting run_enterprise_. Omit it when the set comes from your own payroll system.

instructions InstructionSet required

What is owed to whom for one run. This shape is owned jointly by RUN and REMIT. RUN row 19 emits it and REMIT row 1 ingests it, from RUN and from external payroll alike. It lives here rather than in either module document so the two cannot drift, which is the failure that would otherwise surface at M3 with RUN already accepted and paid. Totals reconcile to run totals to the kobo, because they sum payslip lines rather than recompute from an aggregate. This is the object REMIT ingests.

11 fields of InstructionSet
id string required

The instruction set's identifier, which never changes: read it at GET /v1/payroll/runs/{run_id}/instruction_set when Heros ran the payroll, and send the set on unchanged to POST /v1/remittance/instruction_sets. Quote it when you ask about the set.

object always "instruction_set" required

Always instruction_set. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

run_id string required

The payroll run this set is owed for, by its id from POST /v1/payroll/runs, which starts with run_enterprise_. The set's totals reconcile to that run's totals to the kobo.

period string optional

The pay period the amounts are owed for, as year and month, for example 2026-09.

paye array of object required

Grouped by the State IRS of the employee's residence, not the employer's location.

5 fields
authority_id string required

The State Internal Revenue Service this PAYE is owed to, by its id from GET /v1/remittance/authorities, which starts with remit_authority_rail_obligation_. Use it wherever a call names the authority.

jurisdiction string required

The State Internal Revenue Service this line is grouped under, named in full, for example Rivers State Internal Revenue Service. Read it to label the line; authority_id names the authority in a call.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

payee_count integer optional

How many employees this line's PAYE covers. Optional; when it is present, check it against your own headcount for that state.

reconciliation_reference string required

The reference that identifies this line when you reconcile it, for example paye-2026-09-rivers. Keep it with your own records so you can trace the line later.

pension array of object required

Grouped by administrator and retirement savings account number.

6 fields
administrator_id string required

The Pension Fund Administrator these contributions are owed to, by its id from GET /v1/remittance/authorities with kind=pension_administrator, which starts with remit_authority_rail_obligation_. Use it wherever a call names the administrator.

administrator_name string optional

The administrator's name in full, so you can label the line without a second call. Optional; administrator_id is what names the administrator in a call.

employee_amount Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

employer_amount Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

reconciliation_reference string required

The reference that identifies this line when you reconcile it. Keep it with your own records so you can trace the line later.

levies array of object required

NHF, NSITF, ITF and NHIA totals, each with a reconciliation reference.

3 fields
code string required

Which levy this line is for: nhf the National Housing Fund, nsitf the Nigeria Social Insurance Trust Fund, itf the Industrial Training Fund, nhia the National Health Insurance Authority. One line per levy.

nhfnsitfitfnhia
amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

reconciliation_reference string required

The reference that identifies this levy line when you reconcile it. Keep it with your own records so you can trace the line later.

totals object required

The set's grand total, which its lines sum to. From a Heros run it reconciles to the run's totals to the kobo.

1 field
total Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

created_at string · date-time optional

When the record was created, as an RFC 3339 timestamp in UTC.

Returns

The ingested set, with created_at where there is one, to keep beside your own record.

id string required

The set's identifier, starting remit_authority_rail_instruction_, as listed at GET /v1/remittance/instruction_sets. It never changes; pass it as instruction_set_id to retrieve, accept, reject or remit the set.

object always "ingested_instruction_set" required

Always ingested_instruction_set. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

status string required

Nothing is committed until accepted.

receivedvalidatingpending_acceptanceacceptedrejected
source string required

Where the set came from. Heros payroll or your own, by API or by file. Everything downstream behaves identically whichever it was.

runexternal_apiexternal_file
period string required

The month the set covers, as YYYY-MM, such as 2026-09. Filter the list by it with the period query.

run_id string · nullable optional

The Heros payroll run the set came from, by its id from POST /v1/payroll/runs or GET /v1/payroll/runs, starting run_enterprise_. Present when source is run; null when the set came from your own payroll.

instructions InstructionSet optional

What is owed to whom for one run. This shape is owned jointly by RUN and REMIT. RUN row 19 emits it and REMIT row 1 ingests it, from RUN and from external payroll alike. It lives here rather than in either module document so the two cannot drift, which is the failure that would otherwise surface at M3 with RUN already accepted and paid. Totals reconcile to run totals to the kobo, because they sum payslip lines rather than recompute from an aggregate. This is the object REMIT ingests.

11 fields of InstructionSet
id string required

The instruction set's identifier, which never changes: read it at GET /v1/payroll/runs/{run_id}/instruction_set when Heros ran the payroll, and send the set on unchanged to POST /v1/remittance/instruction_sets. Quote it when you ask about the set.

object always "instruction_set" required

Always instruction_set. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

run_id string required

The payroll run this set is owed for, by its id from POST /v1/payroll/runs, which starts with run_enterprise_. The set's totals reconcile to that run's totals to the kobo.

period string optional

The pay period the amounts are owed for, as year and month, for example 2026-09.

paye array of object required

Grouped by the State IRS of the employee's residence, not the employer's location.

5 fields
authority_id string required

The State Internal Revenue Service this PAYE is owed to, by its id from GET /v1/remittance/authorities, which starts with remit_authority_rail_obligation_. Use it wherever a call names the authority.

jurisdiction string required

The State Internal Revenue Service this line is grouped under, named in full, for example Rivers State Internal Revenue Service. Read it to label the line; authority_id names the authority in a call.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

payee_count integer optional

How many employees this line's PAYE covers. Optional; when it is present, check it against your own headcount for that state.

reconciliation_reference string required

The reference that identifies this line when you reconcile it, for example paye-2026-09-rivers. Keep it with your own records so you can trace the line later.

pension array of object required

Grouped by administrator and retirement savings account number.

6 fields
administrator_id string required

The Pension Fund Administrator these contributions are owed to, by its id from GET /v1/remittance/authorities with kind=pension_administrator, which starts with remit_authority_rail_obligation_. Use it wherever a call names the administrator.

administrator_name string optional

The administrator's name in full, so you can label the line without a second call. Optional; administrator_id is what names the administrator in a call.

employee_amount Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

employer_amount Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

reconciliation_reference string required

The reference that identifies this line when you reconcile it. Keep it with your own records so you can trace the line later.

levies array of object required

NHF, NSITF, ITF and NHIA totals, each with a reconciliation reference.

3 fields
code string required

Which levy this line is for: nhf the National Housing Fund, nsitf the Nigeria Social Insurance Trust Fund, itf the Industrial Training Fund, nhia the National Health Insurance Authority. One line per levy.

nhfnsitfitfnhia
amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

reconciliation_reference string required

The reference that identifies this levy line when you reconcile it. Keep it with your own records so you can trace the line later.

totals object required

The set's grand total, which its lines sum to. From a Heros run it reconciles to the run's totals to the kobo.

1 field
total Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

created_at string · date-time optional

When the record was created, as an RFC 3339 timestamp in UTC.

validation_report ValidationReport required

The result of checking a submission before anything is committed. Names every failing entry rather than stopping at the first, so one submission tells you everything to fix. The same shape wherever the platform ingests, validates and reports, which is every bulk intake in every module.

4 fields of ValidationReport
entry_count integer · minimum 0 required

How many entries the submission held: every row in the file or line in the instruction set, whether it passed or not.

error_count integer · minimum 0 required

How many entries failed with an error. Each is named in entries with its position and why, so one submission tells you everything to fix.

warning_count integer · minimum 0 required

How many entries passed with a warning, each named in entries. A warning does not fail the entry; it points at something to confirm before you go ahead.

entries array of object optional

One item per error or warning found, with the row or line it sits on, its severity, a code and what was wrong. Empty or absent when every entry passed clean.

4 fields
index integer · minimum 1 required

The row in a file, or the line in an instruction set.

severity string required

error means the entry failed and must be fixed. warning means it passed, but points at something you should confirm before you go ahead.

errorwarning
code string required

Why the entry was flagged, as a code you can branch on. detail says the same in words and may change; the code does not.

detail string required

What was wrong with the entry, in plain words. Show it beside the row; it may change, so branch on code.

jurisdiction_pack object optional

The jurisdiction pack the set is pinned to, by identifier and version. Every line was recomputed against it, so its rules are the ones the validation report reflects.

2 fields
pack_id string optional

Which jurisdiction pack the set is pinned to, such as ng-paye. We publish the packs and you never send this; with version, it names exactly which rules every line was checked against, and it stays with the set so you can show which rules applied.

version string optional

The pack version the set was checked against, such as 2026.08.1. It's pinned, so a later pack release doesn't change what this set was judged by.

accepted_by string · nullable optional

Who accepted the set: the actor that called accept. null until the set is accepted.

created_at string · date-time optional

When the record was created, as an RFC 3339 timestamp in UTC.

Other responses

400The request could not be read, or a value was refused.
401No valid credential was presented.
403The credential does not carry the required scope.
422A required fact is missing. Call the readiness endpoint to see what.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X POST "https://sandbox.droomwork.io/v1/remittance/instruction_sets" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"period":"2026-09","instructions":{"id":"remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","object":"instruction_set","livemode":false,"mocked":true,"run_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","paye":[{"authority_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","jurisdiction":"Rivers State Internal Revenue Service","amount":{"amount":7500000,"currency":"NGN"},"reconciliation_reference":"paye-2026-09-rivers","payee_count":1}],"pension":[{"administrator_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","amount":{"amount":7500000,"currency":"NGN"},"reconciliation_reference":"paye-2026-09-rivers","administrator_name":"example","employee_amount":{"amount":4200000,"currency":"NGN"},"employer_amount":{"amount":5400000,"currency":"NGN"}}],"levies":[{"code":"nhf","amount":{"amount":7500000,"currency":"NGN"},"reconciliation_reference":"paye-2026-09-rivers"}],"totals":{"total":{"amount":57900000,"currency":"NGN"}},"period":"2026-09","created_at":"2026-09-01T09:00:00Z"},"run_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"}'
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceInstructionSetsCreate({
  idempotencyKey: crypto.randomUUID(),
  remitInstructionSetCreateRequest: {"period":"2026-09","instructions":{"id":"remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","object":"instruction_set","livemode":false,"mocked":true,"runId":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","paye":[{"authorityId":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","jurisdiction":"Rivers State Internal Revenue Service","amount":{"amount":7500000,"currency":"NGN"},"reconciliationReference":"paye-2026-09-rivers","payeeCount":1}],"pension":[{"administratorId":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","amount":{"amount":7500000,"currency":"NGN"},"reconciliationReference":"paye-2026-09-rivers","administratorName":"example","employeeAmount":{"amount":4200000,"currency":"NGN"},"employerAmount":{"amount":5400000,"currency":"NGN"}}],"levies":[{"code":"nhf","amount":{"amount":7500000,"currency":"NGN"},"reconciliationReference":"paye-2026-09-rivers"}],"totals":{"total":{"amount":57900000,"currency":"NGN"}},"period":"2026-09","createdAt":"2026-09-01T09:00:00Z"},"runId":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"},
});
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/instruction_sets', {
  method: 'POST',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
  },
  body: JSON.stringify({
    "period": "2026-09",
    "instructions": {
      "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "object": "instruction_set",
      "livemode": false,
      "mocked": true,
      "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "paye": [
        {
          "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
          "jurisdiction": "Rivers State Internal Revenue Service",
          "amount": {
            "amount": 7500000,
            "currency": "NGN"
          },
          "reconciliation_reference": "paye-2026-09-rivers",
          "payee_count": 1
        }
      ],
      "pension": [
        {
          "administrator_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
          "amount": {
            "amount": 7500000,
            "currency": "NGN"
          },
          "reconciliation_reference": "paye-2026-09-rivers",
          "administrator_name": "example",
          "employee_amount": {
            "amount": 4200000,
            "currency": "NGN"
          },
          "employer_amount": {
            "amount": 5400000,
            "currency": "NGN"
          }
        }
      ],
      "levies": [
        {
          "code": "nhf",
          "amount": {
            "amount": 7500000,
            "currency": "NGN"
          },
          "reconciliation_reference": "paye-2026-09-rivers"
        }
      ],
      "totals": {
        "total": {
          "amount": 57900000,
          "currency": "NGN"
        }
      },
      "period": "2026-09",
      "created_at": "2026-09-01T09:00:00Z"
    },
    "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
  }),
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_instruction_sets_create(body={"period": "2026-09", "instructions": {"id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "object": "instruction_set", "livemode": False, "mocked": True, "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "paye": [{"authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "jurisdiction": "Rivers State Internal Revenue Service", "amount": {"amount": 7500000, "currency": "NGN"}, "reconciliation_reference": "paye-2026-09-rivers", "payee_count": 1}], "pension": [{"administrator_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "amount": {"amount": 7500000, "currency": "NGN"}, "reconciliation_reference": "paye-2026-09-rivers", "administrator_name": "example", "employee_amount": {"amount": 4200000, "currency": "NGN"}, "employer_amount": {"amount": 5400000, "currency": "NGN"}}], "levies": [{"code": "nhf", "amount": {"amount": 7500000, "currency": "NGN"}, "reconciliation_reference": "paye-2026-09-rivers"}], "totals": {"total": {"amount": 57900000, "currency": "NGN"}}, "period": "2026-09", "created_at": "2026-09-01T09:00:00Z"}, "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"})
import os
import uuid

import requests

response = requests.request(
    'POST',
    'https://sandbox.droomwork.io/v1/remittance/instruction_sets',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
        'Idempotency-Key': str(uuid.uuid4()),
    },
    json={"period": "2026-09", "instructions": {"id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "object": "instruction_set", "livemode": False, "mocked": True, "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "paye": [{"authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "jurisdiction": "Rivers State Internal Revenue Service", "amount": {"amount": 7500000, "currency": "NGN"}, "reconciliation_reference": "paye-2026-09-rivers", "payee_count": 1}], "pension": [{"administrator_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "amount": {"amount": 7500000, "currency": "NGN"}, "reconciliation_reference": "paye-2026-09-rivers", "administrator_name": "example", "employee_amount": {"amount": 4200000, "currency": "NGN"}, "employer_amount": {"amount": 5400000, "currency": "NGN"}}], "levies": [{"code": "nhf", "amount": {"amount": 7500000, "currency": "NGN"}, "reconciliation_reference": "paye-2026-09-rivers"}], "totals": {"total": {"amount": 57900000, "currency": "NGN"}}, "period": "2026-09", "created_at": "2026-09-01T09:00:00Z"}, "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"},
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceInstructionSetsCreate($idempotencyKey, json_decode('{"period":"2026-09","instructions":{"id":"remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","object":"instruction_set","livemode":false,"mocked":true,"run_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","paye":[{"authority_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","jurisdiction":"Rivers State Internal Revenue Service","amount":{"amount":7500000,"currency":"NGN"},"reconciliation_reference":"paye-2026-09-rivers","payee_count":1}],"pension":[{"administrator_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","amount":{"amount":7500000,"currency":"NGN"},"reconciliation_reference":"paye-2026-09-rivers","administrator_name":"example","employee_amount":{"amount":4200000,"currency":"NGN"},"employer_amount":{"amount":5400000,"currency":"NGN"}}],"levies":[{"code":"nhf","amount":{"amount":7500000,"currency":"NGN"},"reconciliation_reference":"paye-2026-09-rivers"}],"totals":{"total":{"amount":57900000,"currency":"NGN"}},"period":"2026-09","created_at":"2026-09-01T09:00:00Z"},"run_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"}', true));
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/instruction_sets');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
    'Content-Type: application/json',
    'Idempotency-Key: ' . bin2hex(random_bytes(16)),
  ],
  CURLOPT_POSTFIELDS => '{"period":"2026-09","instructions":{"id":"remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","object":"instruction_set","livemode":false,"mocked":true,"run_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","paye":[{"authority_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","jurisdiction":"Rivers State Internal Revenue Service","amount":{"amount":7500000,"currency":"NGN"},"reconciliation_reference":"paye-2026-09-rivers","payee_count":1}],"pension":[{"administrator_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","amount":{"amount":7500000,"currency":"NGN"},"reconciliation_reference":"paye-2026-09-rivers","administrator_name":"example","employee_amount":{"amount":4200000,"currency":"NGN"},"employer_amount":{"amount":5400000,"currency":"NGN"}}],"levies":[{"code":"nhf","amount":{"amount":7500000,"currency":"NGN"},"reconciliation_reference":"paye-2026-09-rivers"}],"totals":{"total":{"amount":57900000,"currency":"NGN"}},"period":"2026-09","created_at":"2026-09-01T09:00:00Z"},"run_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"}',
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceInstructionSetsCreate(idempotencyKey, body);
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/instruction_sets"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .header("Content-Type", "application/json")
    .header("Idempotency-Key", UUID.randomUUID().toString())
    .method("POST", HttpRequest.BodyPublishers.ofString("""
        {
          "period": "2026-09",
          "instructions": {
            "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
            "object": "instruction_set",
            "livemode": false,
            "mocked": true,
            "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
            "paye": [
              {
                "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
                "jurisdiction": "Rivers State Internal Revenue Service",
                "amount": {
                  "amount": 7500000,
                  "currency": "NGN"
                },
                "reconciliation_reference": "paye-2026-09-rivers",
                "payee_count": 1
              }
            ],
            "pension": [
              {
                "administrator_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
                "amount": {
                  "amount": 7500000,
                  "currency": "NGN"
                },
                "reconciliation_reference": "paye-2026-09-rivers",
                "administrator_name": "example",
                "employee_amount": {
                  "amount": 4200000,
                  "currency": "NGN"
                },
                "employer_amount": {
                  "amount": 5400000,
                  "currency": "NGN"
                }
              }
            ],
            "levies": [
              {
                "code": "nhf",
                "amount": {
                  "amount": 7500000,
                  "currency": "NGN"
                },
                "reconciliation_reference": "paye-2026-09-rivers"
              }
            ],
            "totals": {
              "total": {
                "amount": 57900000,
                "currency": "NGN"
              }
            },
            "period": "2026-09",
            "created_at": "2026-09-01T09:00:00Z"
          },
          "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
        }
        """))
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceInstructionSetsCreate(idempotencyKey, body);
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/remittance/instruction_sets");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
request.Content = new StringContent("""
    {
      "period": "2026-09",
      "instructions": {
        "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
        "object": "instruction_set",
        "livemode": false,
        "mocked": true,
        "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
        "paye": [
          {
            "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
            "jurisdiction": "Rivers State Internal Revenue Service",
            "amount": {
              "amount": 7500000,
              "currency": "NGN"
            },
            "reconciliation_reference": "paye-2026-09-rivers",
            "payee_count": 1
          }
        ],
        "pension": [
          {
            "administrator_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
            "amount": {
              "amount": 7500000,
              "currency": "NGN"
            },
            "reconciliation_reference": "paye-2026-09-rivers",
            "administrator_name": "example",
            "employee_amount": {
              "amount": 4200000,
              "currency": "NGN"
            },
            "employer_amount": {
              "amount": 5400000,
              "currency": "NGN"
            }
          }
        ],
        "levies": [
          {
            "code": "nhf",
            "amount": {
              "amount": 7500000,
              "currency": "NGN"
            },
            "reconciliation_reference": "paye-2026-09-rivers"
          }
        ],
        "totals": {
          "total": {
            "amount": 57900000,
            "currency": "NGN"
          }
        },
        "period": "2026-09",
        "created_at": "2026-09-01T09:00:00Z"
      },
      "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
    }
    """, Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceInstructionSetsCreate(ctx).IdempotencyKey(key).RemitInstructionSetCreateRequest(body).Execute()
body := strings.NewReader(`{
  "period": "2026-09",
  "instructions": {
    "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
    "object": "instruction_set",
    "livemode": false,
    "mocked": true,
    "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
    "paye": [
      {
        "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
        "jurisdiction": "Rivers State Internal Revenue Service",
        "amount": {
          "amount": 7500000,
          "currency": "NGN"
        },
        "reconciliation_reference": "paye-2026-09-rivers",
        "payee_count": 1
      }
    ],
    "pension": [
      {
        "administrator_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
        "amount": {
          "amount": 7500000,
          "currency": "NGN"
        },
        "reconciliation_reference": "paye-2026-09-rivers",
        "administrator_name": "example",
        "employee_amount": {
          "amount": 4200000,
          "currency": "NGN"
        },
        "employer_amount": {
          "amount": 5400000,
          "currency": "NGN"
        }
      }
    ],
    "levies": [
      {
        "code": "nhf",
        "amount": {
          "amount": 7500000,
          "currency": "NGN"
        },
        "reconciliation_reference": "paye-2026-09-rivers"
      }
    ],
    "totals": {
      "total": {
        "amount": 57900000,
        "currency": "NGN"
      }
    },
    "period": "2026-09",
    "created_at": "2026-09-01T09:00:00Z"
  },
  "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
}`)
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/remittance/instruction_sets", body)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "ingested_instruction_set",
  "livemode": false,
  "mocked": true,
  "status": "received",
  "source": "run",
  "period": "2026-09",
  "validation_report": {
    "entry_count": 0,
    "error_count": 0,
    "warning_count": 0,
    "entries": [
      {
        "index": 1,
        "severity": "error",
        "code": "invalid_money_amount",
        "detail": "The payee has no verified destination, so this line cannot be paid."
      }
    ]
  },
  "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "instructions": {
    "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
    "object": "instruction_set",
    "livemode": false,
    "mocked": true,
    "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
    "paye": [
      {
        "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
        "jurisdiction": "Rivers State Internal Revenue Service",
        "amount": {
          "amount": 7500000,
          "currency": "NGN"
        },
        "reconciliation_reference": "paye-2026-09-rivers",
        "payee_count": 1
      }
    ],
    "pension": [
      {
        "administrator_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
        "amount": {
          "amount": 7500000,
          "currency": "NGN"
        },
        "reconciliation_reference": "paye-2026-09-rivers",
        "administrator_name": "example",
        "employee_amount": {
          "amount": 4200000,
          "currency": "NGN"
        },
        "employer_amount": {
          "amount": 5400000,
          "currency": "NGN"
        }
      }
    ],
    "levies": [
      {
        "code": "nhf",
        "amount": {
          "amount": 7500000,
          "currency": "NGN"
        },
        "reconciliation_reference": "paye-2026-09-rivers"
      }
    ],
    "totals": {
      "total": {
        "amount": 57900000,
        "currency": "NGN"
      }
    },
    "period": "2026-09",
    "created_at": "2026-09-01T09:00:00Z"
  },
  "jurisdiction_pack": {
    "pack_id": "ng-paye",
    "version": "2026.08.1"
  },
  "accepted_by": "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "created_at": "2026-09-01T09:00:00Z"
}
GET/v1/remittance/instruction_sets/{instruction_set_id}#

Read back one submission and its report

remittance.instruction_sets.retrieve

An instruction set is one month's figures as your payroll handed them over, together with the result of checking every line against the jurisdiction pack it is pinned to. Reading one back tells you which rules it was judged by, and that answer holds after a later pack release.

You get the whole record: its state, the figures it holds, the pack identifier and version it was checked against, and the validation report.

The discrepancies the check raised are not on this record. They are their own collection, at GET /v1/remittance/instruction_sets/{instruction_set_id}/discrepancies.

You now hold the month as it was judged, with the pack version to show for it. What it comes to is GET /v1/remittance/instruction_sets/{instruction_set_id}/totals.

Path parameters

instruction_set_id string required

The set's identifier: the id returned by POST /v1/remittance/instruction_sets or listed at GET /v1/remittance/instruction_sets, or an import's instruction_set_id. It starts with remit_authority_rail_instruction_.

Returns

The month as we hold it, traceable to the Heros payroll run behind it when there was one.

id string required

The set's identifier, starting remit_authority_rail_instruction_, as listed at GET /v1/remittance/instruction_sets. It never changes; pass it as instruction_set_id to retrieve, accept, reject or remit the set.

object always "ingested_instruction_set" required

Always ingested_instruction_set. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

status string required

Nothing is committed until accepted.

receivedvalidatingpending_acceptanceacceptedrejected
source string required

Where the set came from. Heros payroll or your own, by API or by file. Everything downstream behaves identically whichever it was.

runexternal_apiexternal_file
period string required

The month the set covers, as YYYY-MM, such as 2026-09. Filter the list by it with the period query.

run_id string · nullable optional

The Heros payroll run the set came from, by its id from POST /v1/payroll/runs or GET /v1/payroll/runs, starting run_enterprise_. Present when source is run; null when the set came from your own payroll.

instructions InstructionSet optional

What is owed to whom for one run. This shape is owned jointly by RUN and REMIT. RUN row 19 emits it and REMIT row 1 ingests it, from RUN and from external payroll alike. It lives here rather than in either module document so the two cannot drift, which is the failure that would otherwise surface at M3 with RUN already accepted and paid. Totals reconcile to run totals to the kobo, because they sum payslip lines rather than recompute from an aggregate. This is the object REMIT ingests.

11 fields of InstructionSet
id string required

The instruction set's identifier, which never changes: read it at GET /v1/payroll/runs/{run_id}/instruction_set when Heros ran the payroll, and send the set on unchanged to POST /v1/remittance/instruction_sets. Quote it when you ask about the set.

object always "instruction_set" required

Always instruction_set. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

run_id string required

The payroll run this set is owed for, by its id from POST /v1/payroll/runs, which starts with run_enterprise_. The set's totals reconcile to that run's totals to the kobo.

period string optional

The pay period the amounts are owed for, as year and month, for example 2026-09.

paye array of object required

Grouped by the State IRS of the employee's residence, not the employer's location.

5 fields
authority_id string required

The State Internal Revenue Service this PAYE is owed to, by its id from GET /v1/remittance/authorities, which starts with remit_authority_rail_obligation_. Use it wherever a call names the authority.

jurisdiction string required

The State Internal Revenue Service this line is grouped under, named in full, for example Rivers State Internal Revenue Service. Read it to label the line; authority_id names the authority in a call.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

payee_count integer optional

How many employees this line's PAYE covers. Optional; when it is present, check it against your own headcount for that state.

reconciliation_reference string required

The reference that identifies this line when you reconcile it, for example paye-2026-09-rivers. Keep it with your own records so you can trace the line later.

pension array of object required

Grouped by administrator and retirement savings account number.

6 fields
administrator_id string required

The Pension Fund Administrator these contributions are owed to, by its id from GET /v1/remittance/authorities with kind=pension_administrator, which starts with remit_authority_rail_obligation_. Use it wherever a call names the administrator.

administrator_name string optional

The administrator's name in full, so you can label the line without a second call. Optional; administrator_id is what names the administrator in a call.

employee_amount Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

employer_amount Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

reconciliation_reference string required

The reference that identifies this line when you reconcile it. Keep it with your own records so you can trace the line later.

levies array of object required

NHF, NSITF, ITF and NHIA totals, each with a reconciliation reference.

3 fields
code string required

Which levy this line is for: nhf the National Housing Fund, nsitf the Nigeria Social Insurance Trust Fund, itf the Industrial Training Fund, nhia the National Health Insurance Authority. One line per levy.

nhfnsitfitfnhia
amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

reconciliation_reference string required

The reference that identifies this levy line when you reconcile it. Keep it with your own records so you can trace the line later.

totals object required

The set's grand total, which its lines sum to. From a Heros run it reconciles to the run's totals to the kobo.

1 field
total Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

created_at string · date-time optional

When the record was created, as an RFC 3339 timestamp in UTC.

validation_report ValidationReport required

The result of checking a submission before anything is committed. Names every failing entry rather than stopping at the first, so one submission tells you everything to fix. The same shape wherever the platform ingests, validates and reports, which is every bulk intake in every module.

4 fields of ValidationReport
entry_count integer · minimum 0 required

How many entries the submission held: every row in the file or line in the instruction set, whether it passed or not.

error_count integer · minimum 0 required

How many entries failed with an error. Each is named in entries with its position and why, so one submission tells you everything to fix.

warning_count integer · minimum 0 required

How many entries passed with a warning, each named in entries. A warning does not fail the entry; it points at something to confirm before you go ahead.

entries array of object optional

One item per error or warning found, with the row or line it sits on, its severity, a code and what was wrong. Empty or absent when every entry passed clean.

4 fields
index integer · minimum 1 required

The row in a file, or the line in an instruction set.

severity string required

error means the entry failed and must be fixed. warning means it passed, but points at something you should confirm before you go ahead.

errorwarning
code string required

Why the entry was flagged, as a code you can branch on. detail says the same in words and may change; the code does not.

detail string required

What was wrong with the entry, in plain words. Show it beside the row; it may change, so branch on code.

jurisdiction_pack object optional

The jurisdiction pack the set is pinned to, by identifier and version. Every line was recomputed against it, so its rules are the ones the validation report reflects.

2 fields
pack_id string optional

Which jurisdiction pack the set is pinned to, such as ng-paye. We publish the packs and you never send this; with version, it names exactly which rules every line was checked against, and it stays with the set so you can show which rules applied.

version string optional

The pack version the set was checked against, such as 2026.08.1. It's pinned, so a later pack release doesn't change what this set was judged by.

accepted_by string · nullable optional

Who accepted the set: the actor that called accept. null until the set is accepted.

created_at string · date-time optional

When the record was created, as an RFC 3339 timestamp in UTC.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X GET "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceInstructionSetsRetrieve({ instructionSetId: 'remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_instruction_sets_retrieve(instruction_set_id='remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')
import os

import requests

response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceInstructionSetsRetrieve(instruction_set_id: 'remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceInstructionSetsRetrieve("remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceInstructionSetsRetrieve(instructionSetId: "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceInstructionSetsRetrieve(ctx, "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "ingested_instruction_set",
  "livemode": false,
  "mocked": true,
  "status": "received",
  "source": "run",
  "period": "2026-09",
  "validation_report": {
    "entry_count": 0,
    "error_count": 0,
    "warning_count": 0,
    "entries": [
      {
        "index": 1,
        "severity": "error",
        "code": "invalid_money_amount",
        "detail": "The payee has no verified destination, so this line cannot be paid."
      }
    ]
  },
  "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "instructions": {
    "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
    "object": "instruction_set",
    "livemode": false,
    "mocked": true,
    "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
    "paye": [
      {
        "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
        "jurisdiction": "Rivers State Internal Revenue Service",
        "amount": {
          "amount": 7500000,
          "currency": "NGN"
        },
        "reconciliation_reference": "paye-2026-09-rivers",
        "payee_count": 1
      }
    ],
    "pension": [
      {
        "administrator_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
        "amount": {
          "amount": 7500000,
          "currency": "NGN"
        },
        "reconciliation_reference": "paye-2026-09-rivers",
        "administrator_name": "example",
        "employee_amount": {
          "amount": 4200000,
          "currency": "NGN"
        },
        "employer_amount": {
          "amount": 5400000,
          "currency": "NGN"
        }
      }
    ],
    "levies": [
      {
        "code": "nhf",
        "amount": {
          "amount": 7500000,
          "currency": "NGN"
        },
        "reconciliation_reference": "paye-2026-09-rivers"
      }
    ],
    "totals": {
      "total": {
        "amount": 57900000,
        "currency": "NGN"
      }
    },
    "period": "2026-09",
    "created_at": "2026-09-01T09:00:00Z"
  },
  "jurisdiction_pack": {
    "pack_id": "ng-paye",
    "version": "2026.08.1"
  },
  "accepted_by": "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "created_at": "2026-09-01T09:00:00Z"
}
POST/v1/remittance/instruction_sets/{instruction_set_id}/accept#

Accept an instruction set for remittance

remittance.instruction_sets.accept

This is the moment the figures are committed. Until it happens nothing is filed against the set, and after it this is the set a remittance is built from, so your product can submit when payroll closes and commit later, when somebody has read the report.

Send no request body. You get the whole set back, with its status now accepted and the validation report you decided on still attached.

The set must be waiting on your decision, which is where POST /v1/remittance/instruction_sets leaves it.

Carry the same instruction_set_id to POST /v1/remittance/remittances, which needs the set accepted. A set that is no longer waiting on your decision is refused with conflict.

Path parameters

instruction_set_id string required

The set's identifier: the id returned by POST /v1/remittance/instruction_sets or listed at GET /v1/remittance/instruction_sets, or an import's instruction_set_id. It starts with remit_authority_rail_instruction_.

Headers

Idempotency-Key string required

A key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.

Returns

The set, with no field on it recording when the decision was taken.

id string required

The set's identifier, starting remit_authority_rail_instruction_, as listed at GET /v1/remittance/instruction_sets. It never changes; pass it as instruction_set_id to retrieve, accept, reject or remit the set.

object always "ingested_instruction_set" required

Always ingested_instruction_set. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

status string required

Nothing is committed until accepted.

receivedvalidatingpending_acceptanceacceptedrejected
source string required

Where the set came from. Heros payroll or your own, by API or by file. Everything downstream behaves identically whichever it was.

runexternal_apiexternal_file
period string required

The month the set covers, as YYYY-MM, such as 2026-09. Filter the list by it with the period query.

run_id string · nullable optional

The Heros payroll run the set came from, by its id from POST /v1/payroll/runs or GET /v1/payroll/runs, starting run_enterprise_. Present when source is run; null when the set came from your own payroll.

instructions InstructionSet optional

What is owed to whom for one run. This shape is owned jointly by RUN and REMIT. RUN row 19 emits it and REMIT row 1 ingests it, from RUN and from external payroll alike. It lives here rather than in either module document so the two cannot drift, which is the failure that would otherwise surface at M3 with RUN already accepted and paid. Totals reconcile to run totals to the kobo, because they sum payslip lines rather than recompute from an aggregate. This is the object REMIT ingests.

11 fields of InstructionSet
id string required

The instruction set's identifier, which never changes: read it at GET /v1/payroll/runs/{run_id}/instruction_set when Heros ran the payroll, and send the set on unchanged to POST /v1/remittance/instruction_sets. Quote it when you ask about the set.

object always "instruction_set" required

Always instruction_set. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

run_id string required

The payroll run this set is owed for, by its id from POST /v1/payroll/runs, which starts with run_enterprise_. The set's totals reconcile to that run's totals to the kobo.

period string optional

The pay period the amounts are owed for, as year and month, for example 2026-09.

paye array of object required

Grouped by the State IRS of the employee's residence, not the employer's location.

5 fields
authority_id string required

The State Internal Revenue Service this PAYE is owed to, by its id from GET /v1/remittance/authorities, which starts with remit_authority_rail_obligation_. Use it wherever a call names the authority.

jurisdiction string required

The State Internal Revenue Service this line is grouped under, named in full, for example Rivers State Internal Revenue Service. Read it to label the line; authority_id names the authority in a call.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

payee_count integer optional

How many employees this line's PAYE covers. Optional; when it is present, check it against your own headcount for that state.

reconciliation_reference string required

The reference that identifies this line when you reconcile it, for example paye-2026-09-rivers. Keep it with your own records so you can trace the line later.

pension array of object required

Grouped by administrator and retirement savings account number.

6 fields
administrator_id string required

The Pension Fund Administrator these contributions are owed to, by its id from GET /v1/remittance/authorities with kind=pension_administrator, which starts with remit_authority_rail_obligation_. Use it wherever a call names the administrator.

administrator_name string optional

The administrator's name in full, so you can label the line without a second call. Optional; administrator_id is what names the administrator in a call.

employee_amount Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

employer_amount Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

reconciliation_reference string required

The reference that identifies this line when you reconcile it. Keep it with your own records so you can trace the line later.

levies array of object required

NHF, NSITF, ITF and NHIA totals, each with a reconciliation reference.

3 fields
code string required

Which levy this line is for: nhf the National Housing Fund, nsitf the Nigeria Social Insurance Trust Fund, itf the Industrial Training Fund, nhia the National Health Insurance Authority. One line per levy.

nhfnsitfitfnhia
amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

reconciliation_reference string required

The reference that identifies this levy line when you reconcile it. Keep it with your own records so you can trace the line later.

totals object required

The set's grand total, which its lines sum to. From a Heros run it reconciles to the run's totals to the kobo.

1 field
total Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

created_at string · date-time optional

When the record was created, as an RFC 3339 timestamp in UTC.

validation_report ValidationReport required

The result of checking a submission before anything is committed. Names every failing entry rather than stopping at the first, so one submission tells you everything to fix. The same shape wherever the platform ingests, validates and reports, which is every bulk intake in every module.

4 fields of ValidationReport
entry_count integer · minimum 0 required

How many entries the submission held: every row in the file or line in the instruction set, whether it passed or not.

error_count integer · minimum 0 required

How many entries failed with an error. Each is named in entries with its position and why, so one submission tells you everything to fix.

warning_count integer · minimum 0 required

How many entries passed with a warning, each named in entries. A warning does not fail the entry; it points at something to confirm before you go ahead.

entries array of object optional

One item per error or warning found, with the row or line it sits on, its severity, a code and what was wrong. Empty or absent when every entry passed clean.

4 fields
index integer · minimum 1 required

The row in a file, or the line in an instruction set.

severity string required

error means the entry failed and must be fixed. warning means it passed, but points at something you should confirm before you go ahead.

errorwarning
code string required

Why the entry was flagged, as a code you can branch on. detail says the same in words and may change; the code does not.

detail string required

What was wrong with the entry, in plain words. Show it beside the row; it may change, so branch on code.

jurisdiction_pack object optional

The jurisdiction pack the set is pinned to, by identifier and version. Every line was recomputed against it, so its rules are the ones the validation report reflects.

2 fields
pack_id string optional

Which jurisdiction pack the set is pinned to, such as ng-paye. We publish the packs and you never send this; with version, it names exactly which rules every line was checked against, and it stays with the set so you can show which rules applied.

version string optional

The pack version the set was checked against, such as 2026.08.1. It's pinned, so a later pack release doesn't change what this set was judged by.

accepted_by string · nullable optional

Who accepted the set: the actor that called accept. null until the set is accepted.

created_at string · date-time optional

When the record was created, as an RFC 3339 timestamp in UTC.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.
409The record is not in a state that allows this.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X POST "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/accept" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceInstructionSetsAccept({ instructionSetId: 'remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/accept', {
  method: 'POST',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
    'Idempotency-Key': crypto.randomUUID(),
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_instruction_sets_accept(instruction_set_id='remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')
import os
import uuid

import requests

response = requests.request(
    'POST',
    'https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/accept',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
        'Idempotency-Key': str(uuid.uuid4()),
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceInstructionSetsAccept(instruction_set_id: 'remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/accept');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
    'Idempotency-Key: ' . bin2hex(random_bytes(16)),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceInstructionSetsAccept("remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/accept"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .header("Idempotency-Key", UUID.randomUUID().toString())
    .method("POST", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceInstructionSetsAccept(instructionSetId: "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/accept");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceInstructionSetsAccept(ctx, "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/accept", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "ingested_instruction_set",
  "livemode": false,
  "mocked": true,
  "status": "accepted",
  "source": "run",
  "period": "2026-09",
  "validation_report": {
    "entry_count": 0,
    "error_count": 0,
    "warning_count": 0,
    "entries": [
      {
        "index": 1,
        "severity": "error",
        "code": "invalid_money_amount",
        "detail": "The payee has no verified destination, so this line cannot be paid."
      }
    ]
  },
  "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "instructions": {
    "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
    "object": "instruction_set",
    "livemode": false,
    "mocked": true,
    "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
    "paye": [
      {
        "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
        "jurisdiction": "Rivers State Internal Revenue Service",
        "amount": {
          "amount": 7500000,
          "currency": "NGN"
        },
        "reconciliation_reference": "paye-2026-09-rivers",
        "payee_count": 1
      }
    ],
    "pension": [
      {
        "administrator_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
        "amount": {
          "amount": 7500000,
          "currency": "NGN"
        },
        "reconciliation_reference": "paye-2026-09-rivers",
        "administrator_name": "example",
        "employee_amount": {
          "amount": 4200000,
          "currency": "NGN"
        },
        "employer_amount": {
          "amount": 5400000,
          "currency": "NGN"
        }
      }
    ],
    "levies": [
      {
        "code": "nhf",
        "amount": {
          "amount": 7500000,
          "currency": "NGN"
        },
        "reconciliation_reference": "paye-2026-09-rivers"
      }
    ],
    "totals": {
      "total": {
        "amount": 57900000,
        "currency": "NGN"
      }
    },
    "period": "2026-09",
    "created_at": "2026-09-01T09:00:00Z"
  },
  "jurisdiction_pack": {
    "pack_id": "ng-paye",
    "version": "2026.08.1"
  },
  "accepted_by": "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "created_at": "2026-09-01T09:00:00Z"
}
GET/v1/remittance/instruction_sets/{instruction_set_id}/totals#

What the month's figures add up to

remittance.instruction_sets.retrieve_totals

This is the number a filing decision rests on: what the month comes to across every authority the set names, in whole minor units with its currency. It also answers whether the figures hold together, so you can check the total before you accept the set and not after it is committed.

You get the grand total with its currency, and a flag saying whether it reconciles: against the originating payroll run when the set came from one, and against the figures' own stated total when it did not.

Nothing else waits on this call. What you hold is one figure to compare with your payroll's own total before you accept the set.

Path parameters

instruction_set_id string required

The set's identifier: the id returned by POST /v1/remittance/instruction_sets or listed at GET /v1/remittance/instruction_sets, or an import's instruction_set_id. It starts with remit_authority_rail_instruction_.

Returns

The totals, with the reconciliation result.

total Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

by_authority array of object optional

One entry per authority the set pays, with the authority's identifier and the amount owed to it, in whole minor units.

2 fields
authority_id string required

The authority this amount is owed to, by its id as listed at GET /v1/remittance/authorities, starting remit_authority_rail_obligation_. Look it up at GET /v1/remittance/authorities/{authority_id} for its name, tier and capabilities.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

reconciles_to_run boolean required

True when the totals match the originating run to the kobo. Absent a run, this reports whether the lines sum to the stated total.

difference Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X GET "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/totals" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceInstructionSetsRetrieveTotals({ instructionSetId: 'remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/totals', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_instruction_sets_retrieve_totals(instruction_set_id='remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')
import os

import requests

response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/totals',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceInstructionSetsRetrieveTotals(instruction_set_id: 'remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/totals');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceInstructionSetsRetrieveTotals("remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/totals"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceInstructionSetsRetrieveTotals(instructionSetId: "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/totals");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceInstructionSetsRetrieveTotals(ctx, "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/totals", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "total": {
    "amount": 57900000,
    "currency": "NGN"
  },
  "reconciles_to_run": true,
  "by_authority": [
    {
      "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "amount": {
        "amount": 7500000,
        "currency": "NGN"
      }
    }
  ],
  "difference": {
    "amount": 10000,
    "currency": "NGN"
  }
}
GET/v1/remittance/instruction_sets/{instruction_set_id}/discrepancies#

See what our validation raised

remittance.discrepancies.list

A discrepancy is a finding our validation raised against your instruction set. Reading them is how a screen in your product shows a reviewer what the validation found, with the figure you submitted beside the one we recomputed.

Send the set's identifier in the path. You get them back, each with its kind, what you submitted, what we recomputed and whether it is still open.

Carry a row's id as discrepancy_id to GET /v1/remittance/instruction_sets/{instruction_set_id}/discrepancies/{discrepancy_id}.

Path parameters

instruction_set_id string required

The set's identifier: the id returned by POST /v1/remittance/instruction_sets or listed at GET /v1/remittance/instruction_sets, or an import's instruction_set_id. It starts with remit_authority_rail_instruction_.

Query parameters

limit integer optional

How many records to return on one page, from 1 to 100, and 25 if you leave it out. When has_more is true, pass the last record's id as starting_after to get the next page.

Returns

A page of discrepancies.

object always "list" required

Always list. Tells you which kind of record you are looking at, so one handler can read any response.

data array of Discrepancy required

The records on this page, in the order the list promises. Empty when nothing matched.

11 fields of Discrepancy
id string required

The discrepancy's identifier, as listed at GET /v1/remittance/instruction_sets/{instruction_set_id}/discrepancies. It never changes; pass it as discrepancy_id when you retrieve or override the discrepancy.

object always "discrepancy" required

Always discrepancy. Tells you which kind of record you are looking at, so one handler can read any response.

kind string required
recomputation_mismatchresidency_conflictmissing_identifierunknown_authority
status string required

open while it blocks acceptance, resolved once it's cleared, overridden once you've kept your submitted figure with a reason code at remittance.discrepancies.override. Acceptance needs none left open.

openresolvedoverridden
line integer optional

Which line of the instruction set the discrepancy is on, counting from 1. Absent when it isn't tied to one line.

subject_id string · nullable optional

The person the discrepancy is about, by the subject_id starting sub_ that's on their payslip at GET /v1/payroll/payslips: for example the employee whose residence puts their PAYE with another State IRS. null otherwise.

submitted Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

recomputed Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

difference Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

reason_code string · nullable optional

The reason code you gave when you overrode the discrepancy, kept on the record permanently. null until it is overridden.

overridden_by string · nullable optional

Who overrode the discrepancy: the actor that supplied the reason code, recorded permanently. null until it is overridden.

has_more boolean required

true when there are more records after this page. Pass the last record's id as starting_after to get the next page.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
# query parameters: limit (optional)
curl -X GET "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies?limit=25" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

// query parameters: limit (optional)
const result = await api.remittanceDiscrepanciesList({ instructionSetId: 'remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', limit: 25 });
// query parameters: limit (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies?limit=25', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

# query parameters: limit (optional)
result = api.remittance_discrepancies_list(instruction_set_id='remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', limit=25)
import os

import requests

# query parameters: limit (optional)
response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies?limit=25',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

# query parameters: limit (optional)
$result = $api->remittanceDiscrepanciesList(instruction_set_id: 'remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', limit: 25);
<?php
// query parameters: limit (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies?limit=25');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

// query parameters: limit (optional)
var result = api.remittanceDiscrepanciesList("remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", 25);
// query parameters: limit (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies?limit=25"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

// query parameters: limit (optional)
var result = api.RemittanceDiscrepanciesList(instructionSetId: "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", limit: 25);
// query parameters: limit (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies?limit=25");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

// query parameters: limit (optional)
result, _, err := client.REMITAPI.RemittanceDiscrepanciesList(ctx, "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Limit(25).Execute()
// query parameters: limit (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies?limit=25", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "object": "list",
  "data": [
    {
      "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "object": "discrepancy",
      "kind": "recomputation_mismatch",
      "status": "open",
      "submitted": {
        "amount": 41250000,
        "currency": "NGN"
      },
      "recomputed": {
        "amount": 41250000,
        "currency": "NGN"
      },
      "line": 1,
      "subject_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "difference": {
        "amount": 10000,
        "currency": "NGN"
      },
      "reason_code": "example",
      "overridden_by": "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
    }
  ],
  "has_more": true
}
GET/v1/remittance/instruction_sets/{instruction_set_id}/discrepancies/{discrepancy_id}#

Compare your figure with ours

remittance.discrepancies.retrieve

This reads one discrepancy back as our validation left it: the figure you submitted and the figure we recomputed against the jurisdiction pack. So a reviewer handed one can put the two figures side by side and decide whether to stand by yours.

Send the set's identifier and the discrepancy's identifier in the path. You get the one record: its kind, both figures in whole minor units with their currency, and whether it is still open.

line is absent when the discrepancy is not tied to one line, and difference is absent when it is not about the figure, so check for each before you print it.

Keep the figure you submitted at POST /v1/remittance/instruction_sets/{instruction_set_id}/discrepancies/{discrepancy_id}/override, passing this id as discrepancy_id.

Path parameters

instruction_set_id string required

The set's identifier: the id returned by POST /v1/remittance/instruction_sets or listed at GET /v1/remittance/instruction_sets, or an import's instruction_set_id. It starts with remit_authority_rail_instruction_.

discrepancy_id string required

The discrepancy's identifier, from the id of a discrepancy listed at GET /v1/remittance/instruction_sets/{instruction_set_id}/discrepancies. It belongs to the set in the path.

Returns

The discrepancy.

id string required

The discrepancy's identifier, as listed at GET /v1/remittance/instruction_sets/{instruction_set_id}/discrepancies. It never changes; pass it as discrepancy_id when you retrieve or override the discrepancy.

object always "discrepancy" required

Always discrepancy. Tells you which kind of record you are looking at, so one handler can read any response.

kind string required
recomputation_mismatchresidency_conflictmissing_identifierunknown_authority
status string required

open while it blocks acceptance, resolved once it's cleared, overridden once you've kept your submitted figure with a reason code at remittance.discrepancies.override. Acceptance needs none left open.

openresolvedoverridden
line integer optional

Which line of the instruction set the discrepancy is on, counting from 1. Absent when it isn't tied to one line.

subject_id string · nullable optional

The person the discrepancy is about, by the subject_id starting sub_ that's on their payslip at GET /v1/payroll/payslips: for example the employee whose residence puts their PAYE with another State IRS. null otherwise.

submitted Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

recomputed Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

difference Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

reason_code string · nullable optional

The reason code you gave when you overrode the discrepancy, kept on the record permanently. null until it is overridden.

overridden_by string · nullable optional

Who overrode the discrepancy: the actor that supplied the reason code, recorded permanently. null until it is overridden.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X GET "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies/%7Bdiscrepancy_id%7D" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceDiscrepanciesRetrieve({ instructionSetId: 'remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', discrepancyId: '{discrepancy_id}' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies/%7Bdiscrepancy_id%7D', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_discrepancies_retrieve(instruction_set_id='remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', discrepancy_id='{discrepancy_id}')
import os

import requests

response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies/%7Bdiscrepancy_id%7D',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceDiscrepanciesRetrieve(instruction_set_id: 'remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', discrepancy_id: '{discrepancy_id}');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies/%7Bdiscrepancy_id%7D');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceDiscrepanciesRetrieve("remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "{discrepancy_id}");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies/%7Bdiscrepancy_id%7D"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceDiscrepanciesRetrieve(instructionSetId: "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", discrepancyId: "{discrepancy_id}");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies/%7Bdiscrepancy_id%7D");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceDiscrepanciesRetrieve(ctx, "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "{discrepancy_id}").Execute()
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies/%7Bdiscrepancy_id%7D", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "discrepancy",
  "kind": "recomputation_mismatch",
  "status": "open",
  "submitted": {
    "amount": 41250000,
    "currency": "NGN"
  },
  "recomputed": {
    "amount": 41250000,
    "currency": "NGN"
  },
  "line": 1,
  "subject_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "difference": {
    "amount": 10000,
    "currency": "NGN"
  },
  "reason_code": "example",
  "overridden_by": "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
}
POST/v1/remittance/instruction_sets/{instruction_set_id}/discrepancies/{discrepancy_id}/override#

Override a discrepancy with a reason

remittance.discrepancies.override

You have read a discrepancy and decided the figure you submitted is the one to keep. Overriding is how you record that decision, so a reviewer working through a set in your product can take each one off the list.

Send a reason_code saying why your figure is the one to keep. You get the whole discrepancy back, both figures unchanged, and its status now overridden.

Call POST /v1/remittance/instruction_sets or POST /v1/remittance/imports first; either one validates your lines and raises the discrepancies you override here.

Accept the set at POST /v1/remittance/instruction_sets/{instruction_set_id}/accept.

Path parameters

instruction_set_id string required

The set's identifier: the id returned by POST /v1/remittance/instruction_sets or listed at GET /v1/remittance/instruction_sets, or an import's instruction_set_id. It starts with remit_authority_rail_instruction_.

discrepancy_id string required

The discrepancy's identifier, from the id of a discrepancy listed at GET /v1/remittance/instruction_sets/{instruction_set_id}/discrepancies. It belongs to the set in the path.

Headers

Idempotency-Key string required

A key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.

Body

reason_code string required

Recorded permanently with the actor who supplied it.

note string optional

Anything a reviewer should know beyond the code, in your words. Optional; it goes on the record with the reason code.

Returns

The discrepancy, with the kind it was raised under, so your record names which finding you set aside.

id string required

The discrepancy's identifier, as listed at GET /v1/remittance/instruction_sets/{instruction_set_id}/discrepancies. It never changes; pass it as discrepancy_id when you retrieve or override the discrepancy.

object always "discrepancy" required

Always discrepancy. Tells you which kind of record you are looking at, so one handler can read any response.

kind string required
recomputation_mismatchresidency_conflictmissing_identifierunknown_authority
status string required

open while it blocks acceptance, resolved once it's cleared, overridden once you've kept your submitted figure with a reason code at remittance.discrepancies.override. Acceptance needs none left open.

openresolvedoverridden
line integer optional

Which line of the instruction set the discrepancy is on, counting from 1. Absent when it isn't tied to one line.

subject_id string · nullable optional

The person the discrepancy is about, by the subject_id starting sub_ that's on their payslip at GET /v1/payroll/payslips: for example the employee whose residence puts their PAYE with another State IRS. null otherwise.

submitted Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

recomputed Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

difference Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

reason_code string · nullable optional

The reason code you gave when you overrode the discrepancy, kept on the record permanently. null until it is overridden.

overridden_by string · nullable optional

Who overrode the discrepancy: the actor that supplied the reason code, recorded permanently. null until it is overridden.

Other responses

400The request could not be read, or a value was refused.
401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.
409The record is not in a state that allows this.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X POST "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies/%7Bdiscrepancy_id%7D/override" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"reason_code":"example","note":"example"}'
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceDiscrepanciesOverride({
  instructionSetId: 'remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z',
  discrepancyId: '{discrepancy_id}',
  idempotencyKey: crypto.randomUUID(),
  remitDiscrepancyOverrideRequest: {"reasonCode":"example","note":"example"},
});
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies/%7Bdiscrepancy_id%7D/override', {
  method: 'POST',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
  },
  body: JSON.stringify({
    "reason_code": "example",
    "note": "example"
  }),
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_discrepancies_override(instruction_set_id='remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', discrepancy_id='{discrepancy_id}', body={"reason_code": "example", "note": "example"})
import os
import uuid

import requests

response = requests.request(
    'POST',
    'https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies/%7Bdiscrepancy_id%7D/override',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
        'Idempotency-Key': str(uuid.uuid4()),
    },
    json={"reason_code": "example", "note": "example"},
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceDiscrepanciesOverride($idempotencyKey, json_decode('{"reason_code":"example","note":"example"}', true));
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies/%7Bdiscrepancy_id%7D/override');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
    'Content-Type: application/json',
    'Idempotency-Key: ' . bin2hex(random_bytes(16)),
  ],
  CURLOPT_POSTFIELDS => '{"reason_code":"example","note":"example"}',
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceDiscrepanciesOverride("remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "{discrepancy_id}", idempotencyKey, body);
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies/%7Bdiscrepancy_id%7D/override"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .header("Content-Type", "application/json")
    .header("Idempotency-Key", UUID.randomUUID().toString())
    .method("POST", HttpRequest.BodyPublishers.ofString("""
        {
          "reason_code": "example",
          "note": "example"
        }
        """))
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceDiscrepanciesOverride(instructionSetId: "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", discrepancyId: "{discrepancy_id}", idempotencyKey, body);
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies/%7Bdiscrepancy_id%7D/override");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
request.Content = new StringContent("""
    {
      "reason_code": "example",
      "note": "example"
    }
    """, Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceDiscrepanciesOverride(ctx, "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "{discrepancy_id}").IdempotencyKey(key).RemitDiscrepancyOverrideRequest(body).Execute()
body := strings.NewReader(`{
  "reason_code": "example",
  "note": "example"
}`)
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/discrepancies/%7Bdiscrepancy_id%7D/override", body)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "discrepancy",
  "kind": "recomputation_mismatch",
  "status": "open",
  "submitted": {
    "amount": 41250000,
    "currency": "NGN"
  },
  "recomputed": {
    "amount": 41250000,
    "currency": "NGN"
  },
  "line": 1,
  "subject_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "difference": {
    "amount": 10000,
    "currency": "NGN"
  },
  "reason_code": "example",
  "overridden_by": "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
}
GET/v1/remittance/imports#

See how your file submissions validated

remittance.imports.list

This gives you every file you have sent for checking, each with the report on the rows it held. So a screen in your product can separate the uploads that came back clean from the ones that still have rows to correct, without opening each one.

Send nothing required. You get the records, each carrying its status, how many rows the file held, how many failed, how many were flagged, and an entry for each failure or flag, naming the row it sits on.

An import does not name the file it came from or the period it covered, so pair its id with both of them.

Read one back at GET /v1/remittance/imports/{import_id}; the list already carries each one whole. Send a corrected file at POST /v1/remittance/imports.

Query parameters

limit integer optional

How many records to return on one page, from 1 to 100, and 25 if you leave it out. When has_more is true, pass the last record's id as starting_after to get the next page.

starting_after string optional

The id of the last record on the previous page of this same list. Leave it out to get the first page; when a page comes back with has_more true, send its last record's id here to get the page after it.

Returns

A page of imports, each with created_at where there is one, which your own log can keep.

object always "list" required

Always list. Tells you which kind of record you are looking at, so one handler can read any response.

data array of Import required

The records on this page, in the order the list promises. Empty when nothing matched.

8 fields of Import
id string required

The import's identifier, assigned at POST /v1/remittance/imports and starting remit_authority_rail_instruction_. It never changes; pass it as import_id at GET /v1/remittance/imports/{import_id} to read the validation report.

object always "remittance_import" required

Always remittance_import. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

status string required

validating while the rows are checked, pending_acceptance once the report is back, accepted or rejected once you accept or reject the instruction set it produced (instruction_set_id). Nothing is committed before accepted.

validatingpending_acceptanceacceptedrejected
instruction_set_id string · nullable optional

The id of the instruction set made from the file, starting remit_authority_rail_instruction_, or null until there is one. Read it at GET /v1/remittance/instruction_sets/{instruction_set_id}, accept or reject it, or list its discrepancies.

validation_report ValidationReport required

The result of checking a submission before anything is committed. Names every failing entry rather than stopping at the first, so one submission tells you everything to fix. The same shape wherever the platform ingests, validates and reports, which is every bulk intake in every module.

4 fields of ValidationReport
entry_count integer · minimum 0 required

How many entries the submission held: every row in the file or line in the instruction set, whether it passed or not.

error_count integer · minimum 0 required

How many entries failed with an error. Each is named in entries with its position and why, so one submission tells you everything to fix.

warning_count integer · minimum 0 required

How many entries passed with a warning, each named in entries. A warning does not fail the entry; it points at something to confirm before you go ahead.

entries array of object optional

One item per error or warning found, with the row or line it sits on, its severity, a code and what was wrong. Empty or absent when every entry passed clean.

4 fields
index integer · minimum 1 required

The row in a file, or the line in an instruction set.

severity string required

error means the entry failed and must be fixed. warning means it passed, but points at something you should confirm before you go ahead.

errorwarning
code string required

Why the entry was flagged, as a code you can branch on. detail says the same in words and may change; the code does not.

detail string required

What was wrong with the entry, in plain words. Show it beside the row; it may change, so branch on code.

created_at string · date-time optional

When the record was created, as an RFC 3339 timestamp in UTC.

has_more boolean required

true when there are more records after this page. Pass the last record's id as starting_after to get the next page.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
# query parameters: limit (optional), starting_after (optional)
curl -X GET "https://sandbox.droomwork.io/v1/remittance/imports?limit=25" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

// query parameters: limit (optional), starting_after (optional)
const result = await api.remittanceImportsList({ limit: 25 });
// query parameters: limit (optional), starting_after (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/imports?limit=25', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

# query parameters: limit (optional), starting_after (optional)
result = api.remittance_imports_list(limit=25)
import os

import requests

# query parameters: limit (optional), starting_after (optional)
response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/imports?limit=25',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

# query parameters: limit (optional), starting_after (optional)
$result = $api->remittanceImportsList(limit: 25);
<?php
// query parameters: limit (optional), starting_after (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/imports?limit=25');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

// query parameters: limit (optional), starting_after (optional)
var result = api.remittanceImportsList(25, null);
// query parameters: limit (optional), starting_after (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/imports?limit=25"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

// query parameters: limit (optional), starting_after (optional)
var result = api.RemittanceImportsList(limit: 25);
// query parameters: limit (optional), starting_after (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/imports?limit=25");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

// query parameters: limit (optional), starting_after (optional)
result, _, err := client.REMITAPI.RemittanceImportsList(ctx).Limit(25).Execute()
// query parameters: limit (optional), starting_after (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/imports?limit=25", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "object": "list",
  "data": [
    {
      "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "object": "remittance_import",
      "livemode": false,
      "mocked": true,
      "status": "validating",
      "validation_report": {
        "entry_count": 0,
        "error_count": 0,
        "warning_count": 0,
        "entries": [
          {
            "index": 1,
            "severity": "error",
            "code": "invalid_money_amount",
            "detail": "The payee has no verified destination, so this line cannot be paid."
          }
        ]
      },
      "instruction_set_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "created_at": "2026-09-01T09:00:00Z"
    }
  ],
  "has_more": true
}
POST/v1/remittance/imports#

Submit an instruction set as a file

remittance.imports.create

This takes a month of statutory figures as a file, for a payroll system that cannot post them to this API. One upload comes back naming every row that failed, so you can put the whole file right in one pass.

Send the file as the file part of a multipart/form-data body, with the period it covers as YYYY-MM. You get the import back with its id and its validation report.

Nothing has to exist first.

An import's id starts remit_authority_rail_instruction_, which is also the prefix an instruction set carries, so keep the two apart in your own store.

A file with failing rows still answers 201: the failures are reported inside the import, not as a refusal. Carry the id as import_id to GET /v1/remittance/imports/{import_id} to read the report again.

Headers

Idempotency-Key string required

A key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.

Returns

The import, carrying no period of its own, though you sent one with the file.

id string required

The import's identifier, assigned at POST /v1/remittance/imports and starting remit_authority_rail_instruction_. It never changes; pass it as import_id at GET /v1/remittance/imports/{import_id} to read the validation report.

object always "remittance_import" required

Always remittance_import. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

status string required

validating while the rows are checked, pending_acceptance once the report is back, accepted or rejected once you accept or reject the instruction set it produced (instruction_set_id). Nothing is committed before accepted.

validatingpending_acceptanceacceptedrejected
instruction_set_id string · nullable optional

The id of the instruction set made from the file, starting remit_authority_rail_instruction_, or null until there is one. Read it at GET /v1/remittance/instruction_sets/{instruction_set_id}, accept or reject it, or list its discrepancies.

validation_report ValidationReport required

The result of checking a submission before anything is committed. Names every failing entry rather than stopping at the first, so one submission tells you everything to fix. The same shape wherever the platform ingests, validates and reports, which is every bulk intake in every module.

4 fields of ValidationReport
entry_count integer · minimum 0 required

How many entries the submission held: every row in the file or line in the instruction set, whether it passed or not.

error_count integer · minimum 0 required

How many entries failed with an error. Each is named in entries with its position and why, so one submission tells you everything to fix.

warning_count integer · minimum 0 required

How many entries passed with a warning, each named in entries. A warning does not fail the entry; it points at something to confirm before you go ahead.

entries array of object optional

One item per error or warning found, with the row or line it sits on, its severity, a code and what was wrong. Empty or absent when every entry passed clean.

4 fields
index integer · minimum 1 required

The row in a file, or the line in an instruction set.

severity string required

error means the entry failed and must be fixed. warning means it passed, but points at something you should confirm before you go ahead.

errorwarning
code string required

Why the entry was flagged, as a code you can branch on. detail says the same in words and may change; the code does not.

detail string required

What was wrong with the entry, in plain words. Show it beside the row; it may change, so branch on code.

created_at string · date-time optional

When the record was created, as an RFC 3339 timestamp in UTC.

Other responses

400The request could not be read, or a value was refused.
401No valid credential was presented.
403The credential does not carry the required scope.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X POST "https://sandbox.droomwork.io/v1/remittance/imports" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceImportsCreate({});
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/imports', {
  method: 'POST',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
    'Idempotency-Key': crypto.randomUUID(),
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_imports_create()
import os
import uuid

import requests

response = requests.request(
    'POST',
    'https://sandbox.droomwork.io/v1/remittance/imports',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
        'Idempotency-Key': str(uuid.uuid4()),
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceImportsCreate();
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/imports');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
    'Idempotency-Key: ' . bin2hex(random_bytes(16)),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceImportsCreate();
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/imports"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .header("Idempotency-Key", UUID.randomUUID().toString())
    .method("POST", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceImportsCreate();
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/remittance/imports");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceImportsCreate(ctx).Execute()
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/remittance/imports", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "remittance_import",
  "livemode": false,
  "mocked": true,
  "status": "validating",
  "validation_report": {
    "entry_count": 0,
    "error_count": 0,
    "warning_count": 0,
    "entries": [
      {
        "index": 1,
        "severity": "error",
        "code": "invalid_money_amount",
        "detail": "The payee has no verified destination, so this line cannot be paid."
      }
    ]
  },
  "instruction_set_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "created_at": "2026-09-01T09:00:00Z"
}
GET/v1/remittance/imports/{import_id}#

Check an upload and the rows that failed

remittance.imports.retrieve

An import is one file you sent and the report on what was in it. This reads that report back from the id alone, so a correction screen in your product can list the rows to fix and nothing else.

Send the import's id in the path. You get its status, the row counts, and an entry for everything that failed or was flagged, each naming the row it sits on, a code to match on and a sentence for a person.

A warning does not fail the row: it passed and points at something to confirm. Only an error has to be fixed.

An import_id nothing matches is refused with not_found. See every upload at GET /v1/remittance/imports, and send a corrected file at POST /v1/remittance/imports.

Path parameters

import_id string required

The import's identifier, from the id returned by POST /v1/remittance/imports or listed at GET /v1/remittance/imports. It starts with remit_authority_rail_instruction_.

Returns

The import, with created_at where there is one, to date the upload in your own store.

id string required

The import's identifier, assigned at POST /v1/remittance/imports and starting remit_authority_rail_instruction_. It never changes; pass it as import_id at GET /v1/remittance/imports/{import_id} to read the validation report.

object always "remittance_import" required

Always remittance_import. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

status string required

validating while the rows are checked, pending_acceptance once the report is back, accepted or rejected once you accept or reject the instruction set it produced (instruction_set_id). Nothing is committed before accepted.

validatingpending_acceptanceacceptedrejected
instruction_set_id string · nullable optional

The id of the instruction set made from the file, starting remit_authority_rail_instruction_, or null until there is one. Read it at GET /v1/remittance/instruction_sets/{instruction_set_id}, accept or reject it, or list its discrepancies.

validation_report ValidationReport required

The result of checking a submission before anything is committed. Names every failing entry rather than stopping at the first, so one submission tells you everything to fix. The same shape wherever the platform ingests, validates and reports, which is every bulk intake in every module.

4 fields of ValidationReport
entry_count integer · minimum 0 required

How many entries the submission held: every row in the file or line in the instruction set, whether it passed or not.

error_count integer · minimum 0 required

How many entries failed with an error. Each is named in entries with its position and why, so one submission tells you everything to fix.

warning_count integer · minimum 0 required

How many entries passed with a warning, each named in entries. A warning does not fail the entry; it points at something to confirm before you go ahead.

entries array of object optional

One item per error or warning found, with the row or line it sits on, its severity, a code and what was wrong. Empty or absent when every entry passed clean.

4 fields
index integer · minimum 1 required

The row in a file, or the line in an instruction set.

severity string required

error means the entry failed and must be fixed. warning means it passed, but points at something you should confirm before you go ahead.

errorwarning
code string required

Why the entry was flagged, as a code you can branch on. detail says the same in words and may change; the code does not.

detail string required

What was wrong with the entry, in plain words. Show it beside the row; it may change, so branch on code.

created_at string · date-time optional

When the record was created, as an RFC 3339 timestamp in UTC.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X GET "https://sandbox.droomwork.io/v1/remittance/imports/%7Bimport_id%7D" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceImportsRetrieve({ importId: '{import_id}' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/imports/%7Bimport_id%7D', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_imports_retrieve(import_id='{import_id}')
import os

import requests

response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/imports/%7Bimport_id%7D',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceImportsRetrieve(import_id: '{import_id}');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/imports/%7Bimport_id%7D');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceImportsRetrieve("{import_id}");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/imports/%7Bimport_id%7D"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceImportsRetrieve(importId: "{import_id}");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/imports/%7Bimport_id%7D");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceImportsRetrieve(ctx, "{import_id}").Execute()
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/imports/%7Bimport_id%7D", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "remittance_import",
  "livemode": false,
  "mocked": true,
  "status": "validating",
  "validation_report": {
    "entry_count": 0,
    "error_count": 0,
    "warning_count": 0,
    "entries": [
      {
        "index": 1,
        "severity": "error",
        "code": "invalid_money_amount",
        "detail": "The payee has no verified destination, so this line cannot be paid."
      }
    ]
  },
  "instruction_set_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "created_at": "2026-09-01T09:00:00Z"
}
GET/v1/remittance/obligations#

What you still owe each authority

remittance.obligations.list

This is the ledger of what you owe each authority: one record for one authority for one month. So your product can show what is outstanding and when it is due, without keeping a deadline table of its own.

Send nothing required. You get the records, each with the authority as authority_id, the month as period, the liability in amount, what has settled against it, what is left in balance, and the date it is due.

Read balance.amount and not balance; balance is the object and amount is the figure.

Pass a record's id as obligation_id to GET /v1/remittance/obligations/{obligation_id}; the list already carries each one whole.

Query parameters

limit integer optional

How many records to return on one page, from 1 to 100, and 25 if you leave it out. When has_more is true, pass the last record's id as starting_after to get the next page.

starting_after string optional

The id of the last record on the previous page of this same list. Leave it out to get the first page; when a page comes back with has_more true, send its last record's id here to get the page after it.

authority_id string optional

Return only what's owed to this authority, by its id as listed at GET /v1/remittance/authorities, starting remit_authority_rail_obligation_. Leave it out to get every authority.

period string optional

Return only obligations for this month, as YYYY-MM, such as 2026-09. Leave it out to get every period.

settled boolean optional

true for obligations with nothing left to pay, false for those with a balance outstanding. Leave it out to get both.

Returns

A page of obligations.

object always "list" required

Always list. Tells you which kind of record you are looking at, so one handler can read any response.

data array of Obligation required

The records on this page, in the order the list promises. Empty when nothing matched.

12 fields of Obligation
id string required

The obligation's identifier, assigned when you accept an instruction set or record one at POST /v1/remittance/obligations, starting remit_authority_rail_obligation_. It never changes; pass it as obligation_id to retrieve it.

object always "obligation" required

Always obligation. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

authority_id string required

The authority the amount is owed to: its id from GET /v1/remittance/authorities, starting remit_authority_rail_obligation_. GET /v1/remittance/authorities/{authority_id} gives its name, tier and capabilities; filter obligations by it.

authority_name string optional

The authority's name as you'd write it, such as Rivers State Internal Revenue Service. For display; authority_id is what you filter and match on.

period string required

The month the liability arises from, as YYYY-MM, such as 2026-09. One obligation covers one authority for one period; filter the list by it with the period query.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

settled Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

balance Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

deadline string · date required

Derived from the pack calendar rules, never entered by hand.

receipt_ids array of string optional

The id of each vaulted receipt that settles against this obligation, empty until one is vaulted. Retrieve a receipt at GET /v1/remittance/receipts/{receipt_id} for the authority's reference and the document.

has_more boolean required

true when there are more records after this page. Pass the last record's id as starting_after to get the next page.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
# query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional), settled (optional)
curl -X GET "https://sandbox.droomwork.io/v1/remittance/obligations?limit=25&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&period=2026-09&settled=false" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

// query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional), settled (optional)
const result = await api.remittanceObligationsList({ limit: 25, authorityId: 'remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', period: '2026-09', settled: false });
// query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional), settled (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/obligations?limit=25&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&period=2026-09&settled=false', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

# query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional), settled (optional)
result = api.remittance_obligations_list(limit=25, authority_id='remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', period='2026-09', settled=false)
import os

import requests

# query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional), settled (optional)
response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/obligations?limit=25&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&period=2026-09&settled=false',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

# query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional), settled (optional)
$result = $api->remittanceObligationsList(limit: 25, authority_id: 'remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', period: '2026-09', settled: false);
<?php
// query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional), settled (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/obligations?limit=25&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&period=2026-09&settled=false');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

// query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional), settled (optional)
var result = api.remittanceObligationsList(25, null, "remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "2026-09", false);
// query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional), settled (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/obligations?limit=25&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&period=2026-09&settled=false"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

// query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional), settled (optional)
var result = api.RemittanceObligationsList(limit: 25, authorityId: "remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", period: "2026-09", settled: false);
// query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional), settled (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/obligations?limit=25&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&period=2026-09&settled=false");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

// query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional), settled (optional)
result, _, err := client.REMITAPI.RemittanceObligationsList(ctx).Limit(25).AuthorityId("remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Period("2026-09").Settled(false).Execute()
// query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional), settled (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/obligations?limit=25&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&period=2026-09&settled=false", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "object": "list",
  "data": [
    {
      "id": "remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "object": "obligation",
      "livemode": false,
      "mocked": true,
      "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "period": "2026-09",
      "amount": {
        "amount": 7500000,
        "currency": "NGN"
      },
      "settled": {
        "amount": 41250000,
        "currency": "NGN"
      },
      "balance": {
        "amount": 41250000,
        "currency": "NGN"
      },
      "deadline": "2026-09-01",
      "authority_name": "Sandbox State Internal Revenue Service",
      "receipt_ids": [
        "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
      ]
    }
  ],
  "has_more": true
}
POST/v1/remittance/obligations#

Record a liability you already owe

remittance.obligations.create

This records a liability you owe an authority as an obligation of its own. So a debt that reached you from somewhere else is held in the same ledger, and reads back exactly like any obligation at GET /v1/remittance/obligations.

Send the period the liability arises from, as YYYY-MM. You get the obligation back with its own id, the authority it is owed to, the amount, what has settled against it, the balance left to pay and the date it is due.

Nothing has to exist first.

One obligation covers one authority for one period, so a second month or a second authority is a second call.

Carry the id as obligation_id to GET /v1/remittance/obligations/{obligation_id} to read the record back, and see the whole ledger at GET /v1/remittance/obligations.

Headers

Idempotency-Key string required

A key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.

Body optional

authority string optional

The authority the amount is owed to.

period string optional

The period the obligation arises from, as YYYY-MM.

Returns

The recorded obligation.

id string required

The obligation's identifier, assigned when you accept an instruction set or record one at POST /v1/remittance/obligations, starting remit_authority_rail_obligation_. It never changes; pass it as obligation_id to retrieve it.

object always "obligation" required

Always obligation. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

authority_id string required

The authority the amount is owed to: its id from GET /v1/remittance/authorities, starting remit_authority_rail_obligation_. GET /v1/remittance/authorities/{authority_id} gives its name, tier and capabilities; filter obligations by it.

authority_name string optional

The authority's name as you'd write it, such as Rivers State Internal Revenue Service. For display; authority_id is what you filter and match on.

period string required

The month the liability arises from, as YYYY-MM, such as 2026-09. One obligation covers one authority for one period; filter the list by it with the period query.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

settled Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

balance Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

deadline string · date required

Derived from the pack calendar rules, never entered by hand.

receipt_ids array of string optional

The id of each vaulted receipt that settles against this obligation, empty until one is vaulted. Retrieve a receipt at GET /v1/remittance/receipts/{receipt_id} for the authority's reference and the document.

Other responses

400The request could not be read, or a value was refused.
401No valid credential was presented.
403The credential does not carry the required scope.
409The record is not in a state that allows this.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X POST "https://sandbox.droomwork.io/v1/remittance/obligations" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"authority":"example","period":"2026-09"}'
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceObligationsCreate({});
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/obligations', {
  method: 'POST',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
  },
  body: JSON.stringify({
    "authority": "example",
    "period": "2026-09"
  }),
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_obligations_create()
import os
import uuid

import requests

response = requests.request(
    'POST',
    'https://sandbox.droomwork.io/v1/remittance/obligations',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
        'Idempotency-Key': str(uuid.uuid4()),
    },
    json={"authority": "example", "period": "2026-09"},
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceObligationsCreate();
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/obligations');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
    'Content-Type: application/json',
    'Idempotency-Key: ' . bin2hex(random_bytes(16)),
  ],
  CURLOPT_POSTFIELDS => '{"authority":"example","period":"2026-09"}',
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceObligationsCreate();
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/obligations"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .header("Content-Type", "application/json")
    .header("Idempotency-Key", UUID.randomUUID().toString())
    .method("POST", HttpRequest.BodyPublishers.ofString("""
        {
          "authority": "example",
          "period": "2026-09"
        }
        """))
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceObligationsCreate();
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/remittance/obligations");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
request.Content = new StringContent("""
    {
      "authority": "example",
      "period": "2026-09"
    }
    """, Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceObligationsCreate(ctx).Execute()
body := strings.NewReader(`{
  "authority": "example",
  "period": "2026-09"
}`)
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/remittance/obligations", body)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "obligation",
  "livemode": false,
  "mocked": true,
  "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "period": "2026-09",
  "amount": {
    "amount": 7500000,
    "currency": "NGN"
  },
  "settled": {
    "amount": 41250000,
    "currency": "NGN"
  },
  "balance": {
    "amount": 41250000,
    "currency": "NGN"
  },
  "deadline": "2026-09-01",
  "authority_name": "Sandbox State Internal Revenue Service",
  "receipt_ids": [
    "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
  ]
}
GET/v1/remittance/obligations/{obligation_id}#

Check one liability and its balance

remittance.obligations.retrieve

An obligation is what you owe one authority for one month: the liability, what has settled against it, the balance left to pay, and the date it is due. So one identifier your system already stores puts the liability, the balance and the due date on a screen, and you keep no figures of your own.

Send the obligation's id in the path, which starts remit_authority_rail_obligation_. You get that one record back whole, with the authority named as well as identified.

Read balance.amount and not balance; balance is the object and amount is the figure.

The deadline comes with the record and is not something you set.

An obligation_id nothing holds answers not_found. See the whole ledger at GET /v1/remittance/obligations.

Path parameters

obligation_id string required

The obligation's identifier, from the id of an obligation listed at GET /v1/remittance/obligations or recorded at POST /v1/remittance/obligations. It starts with remit_authority_rail_obligation_.

Returns

The obligation.

id string required

The obligation's identifier, assigned when you accept an instruction set or record one at POST /v1/remittance/obligations, starting remit_authority_rail_obligation_. It never changes; pass it as obligation_id to retrieve it.

object always "obligation" required

Always obligation. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

authority_id string required

The authority the amount is owed to: its id from GET /v1/remittance/authorities, starting remit_authority_rail_obligation_. GET /v1/remittance/authorities/{authority_id} gives its name, tier and capabilities; filter obligations by it.

authority_name string optional

The authority's name as you'd write it, such as Rivers State Internal Revenue Service. For display; authority_id is what you filter and match on.

period string required

The month the liability arises from, as YYYY-MM, such as 2026-09. One obligation covers one authority for one period; filter the list by it with the period query.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

settled Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

balance Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

deadline string · date required

Derived from the pack calendar rules, never entered by hand.

receipt_ids array of string optional

The id of each vaulted receipt that settles against this obligation, empty until one is vaulted. Retrieve a receipt at GET /v1/remittance/receipts/{receipt_id} for the authority's reference and the document.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X GET "https://sandbox.droomwork.io/v1/remittance/obligations/remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceObligationsRetrieve({ obligationId: 'remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/obligations/remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_obligations_retrieve(obligation_id='remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')
import os

import requests

response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/obligations/remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceObligationsRetrieve(obligation_id: 'remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/obligations/remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceObligationsRetrieve("remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/obligations/remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceObligationsRetrieve(obligationId: "remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/obligations/remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceObligationsRetrieve(ctx, "remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/obligations/remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "obligation",
  "livemode": false,
  "mocked": true,
  "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "period": "2026-09",
  "amount": {
    "amount": 7500000,
    "currency": "NGN"
  },
  "settled": {
    "amount": 41250000,
    "currency": "NGN"
  },
  "balance": {
    "amount": 41250000,
    "currency": "NGN"
  },
  "deadline": "2026-09-01",
  "authority_name": "Sandbox State Internal Revenue Service",
  "receipt_ids": [
    "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
  ]
}
GET/v1/remittance/calendar_entries#

See when each filing falls due

remittance.calendar_entries.list

This is your statutory filing calendar: what falls due to each authority, and for which month. So a deadline screen in your product gets its dates from the jurisdiction pack, and never from anything you typed in.

You send nothing. Each entry names the authority in authority_id, the month it covers in period, the date the filing is due in deadline, and what is owed by then in amount, in whole minor units with its currency.

penalty_formula is text from the pack and not a figure: what filing late costs depends on when you file. Show it; do not compute with it.

Read one at GET /v1/remittance/calendar_entries/{calendar_entry_id}, passing an entry's id. A calendar entry says what is due and when; what is still outstanding sits on the obligation, at GET /v1/remittance/obligations.

Query parameters

limit integer optional

How many records to return on one page, from 1 to 100, and 25 if you leave it out. When has_more is true, pass the last record's id as starting_after to get the next page.

due_before string optional

Return only deadlines that fall before this date, as YYYY-MM-DD, such as 2026-09-30. Leave it out to get every deadline.

authority_id string optional

Return only the deadlines for this authority, by its id as listed at GET /v1/remittance/authorities, starting remit_authority_rail_obligation_. Leave it out to get every authority.

Returns

A page of calendar entries, each carrying its own lead time where there is one.

object always "list" required

Always list. Tells you which kind of record you are looking at, so one handler can read any response.

data array of CalendarEntry required

The records on this page, in the order the list promises. Empty when nothing matched.

10 fields of CalendarEntry
id string required

The deadline's identifier, as listed at GET /v1/remittance/calendar_entries, starting remit_authority_rail_obligation_. It never changes; pass it as calendar_entry_id at GET /v1/remittance/calendar_entries/{calendar_entry_id}.

object always "calendar_entry" required

Always calendar_entry. Tells you which kind of record you are looking at, so one handler can read any response.

authority_id string required

The authority this deadline is for: its id from GET /v1/remittance/authorities, starting remit_authority_rail_obligation_. GET /v1/remittance/authorities/{authority_id} gives its name, tier and capabilities; filter the calendar by it.

authority_name string optional

The authority's name as you'd write it, such as Rivers State Internal Revenue Service. For display; authority_id is what you filter and match on.

period string required

The month the filing covers, as YYYY-MM, such as 2026-09. The deadline and amount are for this period alone.

deadline string · date required

The date the filing is due, as YYYY-MM-DD, such as 2026-09-01, set by the jurisdiction pack's calendar rules and never by anything you enter. File after it and penalty_formula says what that costs.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

penalty_formula string optional

Published from the pack as a formula rather than a computed figure, because the amount depends on when you actually file.

lead_time_days integer optional

How far ahead the due soon alert fires.

pack_version string optional

The version of the jurisdiction pack this entry came from, such as 2026.08.1. Keep it with the entry, so you can show which rules set the deadline and the penalty formula.

has_more boolean required

true when there are more records after this page. Pass the last record's id as starting_after to get the next page.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
# query parameters: limit (optional), due_before (optional), authority_id (optional)
curl -X GET "https://sandbox.droomwork.io/v1/remittance/calendar_entries?limit=25&due_before=2026-09-30&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

// query parameters: limit (optional), due_before (optional), authority_id (optional)
const result = await api.remittanceCalendarEntriesList({ limit: 25, dueBefore: '2026-09-30', authorityId: 'remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });
// query parameters: limit (optional), due_before (optional), authority_id (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/calendar_entries?limit=25&due_before=2026-09-30&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

# query parameters: limit (optional), due_before (optional), authority_id (optional)
result = api.remittance_calendar_entries_list(limit=25, due_before='2026-09-30', authority_id='remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')
import os

import requests

# query parameters: limit (optional), due_before (optional), authority_id (optional)
response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/calendar_entries?limit=25&due_before=2026-09-30&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

# query parameters: limit (optional), due_before (optional), authority_id (optional)
$result = $api->remittanceCalendarEntriesList(limit: 25, due_before: '2026-09-30', authority_id: 'remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
<?php
// query parameters: limit (optional), due_before (optional), authority_id (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/calendar_entries?limit=25&due_before=2026-09-30&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

// query parameters: limit (optional), due_before (optional), authority_id (optional)
var result = api.remittanceCalendarEntriesList(25, "2026-09-30", "remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
// query parameters: limit (optional), due_before (optional), authority_id (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/calendar_entries?limit=25&due_before=2026-09-30&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

// query parameters: limit (optional), due_before (optional), authority_id (optional)
var result = api.RemittanceCalendarEntriesList(limit: 25, dueBefore: "2026-09-30", authorityId: "remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
// query parameters: limit (optional), due_before (optional), authority_id (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/calendar_entries?limit=25&due_before=2026-09-30&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

// query parameters: limit (optional), due_before (optional), authority_id (optional)
result, _, err := client.REMITAPI.RemittanceCalendarEntriesList(ctx).Limit(25).DueBefore("2026-09-30").AuthorityId("remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()
// query parameters: limit (optional), due_before (optional), authority_id (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/calendar_entries?limit=25&due_before=2026-09-30&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "object": "list",
  "data": [
    {
      "id": "remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "object": "calendar_entry",
      "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "period": "2026-09",
      "deadline": "2026-09-01",
      "amount": {
        "amount": 7500000,
        "currency": "NGN"
      },
      "authority_name": "Sandbox State Internal Revenue Service",
      "penalty_formula": "10 percent of the unpaid amount plus interest at the CBN rate per annum",
      "lead_time_days": 1,
      "pack_version": "2026.08.1"
    }
  ],
  "has_more": true
}
GET/v1/remittance/calendar_entries/{calendar_entry_id}#

Check one filing deadline on its own

remittance.calendar_entries.retrieve

A calendar entry is one filing deadline: one authority, one month, the date it is due, and what is owed by then. So one identifier you stored puts that deadline back on a screen, without reading the whole calendar to find it again.

Send the entry's id in the path as calendar_entry_id. You get the whole entry back, with amount in whole minor units with its currency and penalty_formula as the terms that apply if you file after the deadline.

An id nothing holds answers not_found. Other entries are listed at GET /v1/remittance/calendar_entries.

Path parameters

calendar_entry_id string required

The deadline's identifier, from the id of an entry listed at GET /v1/remittance/calendar_entries. It starts with remit_authority_rail_obligation_.

Returns

The deadline itself, with the lead time that says how early to warn whoever must file.

id string required

The deadline's identifier, as listed at GET /v1/remittance/calendar_entries, starting remit_authority_rail_obligation_. It never changes; pass it as calendar_entry_id at GET /v1/remittance/calendar_entries/{calendar_entry_id}.

object always "calendar_entry" required

Always calendar_entry. Tells you which kind of record you are looking at, so one handler can read any response.

authority_id string required

The authority this deadline is for: its id from GET /v1/remittance/authorities, starting remit_authority_rail_obligation_. GET /v1/remittance/authorities/{authority_id} gives its name, tier and capabilities; filter the calendar by it.

authority_name string optional

The authority's name as you'd write it, such as Rivers State Internal Revenue Service. For display; authority_id is what you filter and match on.

period string required

The month the filing covers, as YYYY-MM, such as 2026-09. The deadline and amount are for this period alone.

deadline string · date required

The date the filing is due, as YYYY-MM-DD, such as 2026-09-01, set by the jurisdiction pack's calendar rules and never by anything you enter. File after it and penalty_formula says what that costs.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

penalty_formula string optional

Published from the pack as a formula rather than a computed figure, because the amount depends on when you actually file.

lead_time_days integer optional

How far ahead the due soon alert fires.

pack_version string optional

The version of the jurisdiction pack this entry came from, such as 2026.08.1. Keep it with the entry, so you can show which rules set the deadline and the penalty formula.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X GET "https://sandbox.droomwork.io/v1/remittance/calendar_entries/%7Bcalendar_entry_id%7D" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceCalendarEntriesRetrieve({ calendarEntryId: '{calendar_entry_id}' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/calendar_entries/%7Bcalendar_entry_id%7D', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_calendar_entries_retrieve(calendar_entry_id='{calendar_entry_id}')
import os

import requests

response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/calendar_entries/%7Bcalendar_entry_id%7D',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceCalendarEntriesRetrieve(calendar_entry_id: '{calendar_entry_id}');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/calendar_entries/%7Bcalendar_entry_id%7D');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceCalendarEntriesRetrieve("{calendar_entry_id}");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/calendar_entries/%7Bcalendar_entry_id%7D"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceCalendarEntriesRetrieve(calendarEntryId: "{calendar_entry_id}");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/calendar_entries/%7Bcalendar_entry_id%7D");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceCalendarEntriesRetrieve(ctx, "{calendar_entry_id}").Execute()
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/calendar_entries/%7Bcalendar_entry_id%7D", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "calendar_entry",
  "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "period": "2026-09",
  "deadline": "2026-09-01",
  "amount": {
    "amount": 7500000,
    "currency": "NGN"
  },
  "authority_name": "Sandbox State Internal Revenue Service",
  "penalty_formula": "10 percent of the unpaid amount plus interest at the CBN rate per annum",
  "lead_time_days": 1,
  "pack_version": "2026.08.1"
}
GET/v1/remittance/authorities#

Find the authority you file with

remittance.authorities.list

An authority is a body you owe money to: a tax office, a pension body, or one of the statutory levies. This is the register of them, so your product can offer a list to pick from instead of a free text box.

You send nothing. Each authority comes back with its name, its kind, a tier, and a capabilities object answering separately for paying it, filing a return, uploading a schedule and retrieving a receipt.

Read capabilities before you build against an authority: the four answers are independent, so one may take a filing and not a payment.

Keep an authority's id and pass it as authority_id to read one on its own at GET /v1/remittance/authorities/{authority_id}.

Query parameters

limit integer optional

How many records to return on one page, from 1 to 100, and 25 if you leave it out. When has_more is true, pass the last record's id as starting_after to get the next page.

kind string optional

Return only authorities of this kind: state_irs or federal_irs for tax, pension_commission or pension_administrator for pensions, nhf, nsitf, itf or nhia for the levies. Leave it out to get every kind.

state_irsfederal_irspension_commissionpension_administratornhfnsitfitfnhia
tier string optional

Return only authorities your filing reaches this way: direct_api, portal_automation or assisted_manual. Leave it out to get every tier; read a tier for timing, never as something to code against.

direct_apiportal_automationassisted_manual

Returns

A page of authorities.

object always "list" required

Always list. Tells you which kind of record you are looking at, so one handler can read any response.

data array of Authority required

The records on this page, in the order the list promises. Empty when nothing matched.

9 fields of Authority
id string required

The authority's identifier, as listed at GET /v1/remittance/authorities, starting remit_authority_rail_obligation_. It never changes; pass it as authority_id to retrieve the authority, or to filter obligations and deadlines by it.

object always "authority" required

Always authority. Tells you which kind of record you are looking at, so one handler can read any response.

kind string required
state_irsfederal_irspension_commissionpension_administratornhfnsitfitfnhia
tier string required

How the filing reaches the authority. Readable so you know what to expect on timing. Never something to code against, since all three present the same contract.

direct_apiportal_automationassisted_manual
name string required

The authority's name as you'd write it, such as Rivers State Internal Revenue Service. It's what appears as authority_name on obligations, legs and deadlines.

jurisdiction string optional

Which jurisdiction the authority collects for, such as the state whose PAYE a State IRS receives. Use it to tell the 37 tax jurisdictions apart.

capabilities object required

What this authority supports. Absent a capability, the endpoint refuses rather than pretends.

4 fields
file_return boolean optional

true when you can file an employer return with this authority through Heros. When it's false, a return for this authority is refused rather than pretended.

pay boolean optional

true when you can pay this authority through a remittance leg. When it's false, a leg for this authority is refused rather than pretended.

receipt_retrieval boolean optional

true when we can retrieve the receipt for a filing from this authority and vault it as your proof. When it's false, none is retrieved for you: record the one the authority issued at POST /v1/remittance/receipts.

schedule_upload boolean optional

true when the per-employee schedule behind a filing can be uploaded to this authority. When it's false, a schedule upload for it is refused rather than pretended.

credentials_held boolean optional

Whether you have supplied credentials for this authority.

expected_completion string optional

Typical time to a vaulted receipt at this tier.

has_more boolean required

true when there are more records after this page. Pass the last record's id as starting_after to get the next page.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
# query parameters: limit (optional), kind (optional), tier (optional)
curl -X GET "https://sandbox.droomwork.io/v1/remittance/authorities?limit=25&kind=state_irs&tier=direct_api" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

// query parameters: limit (optional), kind (optional), tier (optional)
const result = await api.remittanceAuthoritiesList({ limit: 25, kind: 'state_irs', tier: 'direct_api' });
// query parameters: limit (optional), kind (optional), tier (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/authorities?limit=25&kind=state_irs&tier=direct_api', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

# query parameters: limit (optional), kind (optional), tier (optional)
result = api.remittance_authorities_list(limit=25, kind='state_irs', tier='direct_api')
import os

import requests

# query parameters: limit (optional), kind (optional), tier (optional)
response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/authorities?limit=25&kind=state_irs&tier=direct_api',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

# query parameters: limit (optional), kind (optional), tier (optional)
$result = $api->remittanceAuthoritiesList(limit: 25, kind: 'state_irs', tier: 'direct_api');
<?php
// query parameters: limit (optional), kind (optional), tier (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/authorities?limit=25&kind=state_irs&tier=direct_api');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;
import com.useheros.sdk.model.*;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

// query parameters: limit (optional), kind (optional), tier (optional)
var result = api.remittanceAuthoritiesList(25, RemitAuthorityKind.fromValue("state_irs"), RemitAuthorityTier.fromValue("direct_api"));
// query parameters: limit (optional), kind (optional), tier (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/authorities?limit=25&kind=state_irs&tier=direct_api"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

// query parameters: limit (optional), kind (optional), tier (optional)
var result = api.RemittanceAuthoritiesList(limit: 25, kind: RemitAuthorityKind.StateIrs, tier: RemitAuthorityTier.DirectApi);
// query parameters: limit (optional), kind (optional), tier (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/authorities?limit=25&kind=state_irs&tier=direct_api");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

// query parameters: limit (optional), kind (optional), tier (optional)
result, _, err := client.REMITAPI.RemittanceAuthoritiesList(ctx).Limit(25).Kind(heros.RemitAuthorityKind("state_irs")).Tier(heros.RemitAuthorityTier("direct_api")).Execute()
// query parameters: limit (optional), kind (optional), tier (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/authorities?limit=25&kind=state_irs&tier=direct_api", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "object": "list",
  "data": [
    {
      "id": "remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "object": "authority",
      "kind": "state_irs",
      "tier": "direct_api",
      "name": "Rivers State Internal Revenue Service",
      "capabilities": {
        "file_return": true,
        "pay": true,
        "receipt_retrieval": true,
        "schedule_upload": true
      },
      "jurisdiction": "Sandbox State Internal Revenue Service",
      "credentials_held": true,
      "expected_completion": "under 5 minutes"
    }
  ],
  "has_more": true
}
GET/v1/remittance/authorities/{authority_id}#

Check what one authority supports

remittance.authorities.retrieve

An authority is a body you owe money to, and this reads one of them back on its own: who it is, how a filing reaches it, and what it accepts. So a page in your product can offer what may be done with that authority, and leave out the rest.

Send the authority's id in the path as authority_id. You get the authority back: its name, its kind, its tier, and the capabilities it answers for.

expected_completion is free text and typical of the tier, not a promise about one filing: show it, and do not parse it.

An id nothing holds answers not_found. Other authorities are listed at GET /v1/remittance/authorities.

Path parameters

authority_id string required

The authority's identifier: the id of an authority listed at GET /v1/remittance/authorities, or the authority_id on an obligation, leg, receipt or calendar entry. It starts with remit_authority_rail_obligation_.

Returns

One authority in full, with the typical time to a receipt there, to set a caller's expectations.

id string required

The authority's identifier, as listed at GET /v1/remittance/authorities, starting remit_authority_rail_obligation_. It never changes; pass it as authority_id to retrieve the authority, or to filter obligations and deadlines by it.

object always "authority" required

Always authority. Tells you which kind of record you are looking at, so one handler can read any response.

kind string required
state_irsfederal_irspension_commissionpension_administratornhfnsitfitfnhia
tier string required

How the filing reaches the authority. Readable so you know what to expect on timing. Never something to code against, since all three present the same contract.

direct_apiportal_automationassisted_manual
name string required

The authority's name as you'd write it, such as Rivers State Internal Revenue Service. It's what appears as authority_name on obligations, legs and deadlines.

jurisdiction string optional

Which jurisdiction the authority collects for, such as the state whose PAYE a State IRS receives. Use it to tell the 37 tax jurisdictions apart.

capabilities object required

What this authority supports. Absent a capability, the endpoint refuses rather than pretends.

4 fields
file_return boolean optional

true when you can file an employer return with this authority through Heros. When it's false, a return for this authority is refused rather than pretended.

pay boolean optional

true when you can pay this authority through a remittance leg. When it's false, a leg for this authority is refused rather than pretended.

receipt_retrieval boolean optional

true when we can retrieve the receipt for a filing from this authority and vault it as your proof. When it's false, none is retrieved for you: record the one the authority issued at POST /v1/remittance/receipts.

schedule_upload boolean optional

true when the per-employee schedule behind a filing can be uploaded to this authority. When it's false, a schedule upload for it is refused rather than pretended.

credentials_held boolean optional

Whether you have supplied credentials for this authority.

expected_completion string optional

Typical time to a vaulted receipt at this tier.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X GET "https://sandbox.droomwork.io/v1/remittance/authorities/%7Bauthority_id%7D" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceAuthoritiesRetrieve({ authorityId: '{authority_id}' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/authorities/%7Bauthority_id%7D', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_authorities_retrieve(authority_id='{authority_id}')
import os

import requests

response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/authorities/%7Bauthority_id%7D',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceAuthoritiesRetrieve(authority_id: '{authority_id}');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/authorities/%7Bauthority_id%7D');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceAuthoritiesRetrieve("{authority_id}");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/authorities/%7Bauthority_id%7D"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceAuthoritiesRetrieve(authorityId: "{authority_id}");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/authorities/%7Bauthority_id%7D");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceAuthoritiesRetrieve(ctx, "{authority_id}").Execute()
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/authorities/%7Bauthority_id%7D", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "authority",
  "kind": "state_irs",
  "tier": "direct_api",
  "name": "Rivers State Internal Revenue Service",
  "capabilities": {
    "file_return": true,
    "pay": true,
    "receipt_retrieval": true,
    "schedule_upload": true
  },
  "jurisdiction": "Sandbox State Internal Revenue Service",
  "credentials_held": true,
  "expected_completion": "under 5 minutes"
}
GET/v1/remittance/remittances#

Find a remittance you opened earlier

remittance.remittances.list

This hands you the remittances your organisation has created, each one a month's payment to the authorities. A record comes back whole, figures and legs together, so a filing screen in your product needs no second call for each row, and an id you did not keep is found again here.

You send nothing. Each record carries the state that remittance has reached, its total in whole minor units with its currency, the instruction set it was built from, and each leg with its own state and amount.

Carry a record's id as remittance_id to read the same remittance at GET /v1/remittance/remittances/{remittance_id}, or its legs on their own at GET /v1/remittance/remittances/{remittance_id}/legs.

Query parameters

limit integer optional

How many records to return on one page, from 1 to 100, and 25 if you leave it out. When has_more is true, pass the last record's id as starting_after to get the next page.

starting_after string optional

The id of the last record on the previous page of this same list. Leave it out to get the first page; when a page comes back with has_more true, send its last record's id here to get the page after it.

status string optional

Return only remittances in one state: draft (created, not yet approved), approved, executing (legs running), completed, partially_completed (some legs failed) or failed. Leave it out to get every state.

draftapprovedexecutingcompletedpartially_completedfailed

Returns

A page of remittances, each carrying the month it pays where there is one.

object always "list" required

Always list. Tells you which kind of record you are looking at, so one handler can read any response.

data array of Remittance required

The records on this page, in the order the list promises. Empty when nothing matched.

11 fields of Remittance
id string required

The remittance's identifier, first returned by POST /v1/remittance/remittances; it starts with remit_authority_rail_remittance_ and never changes. Pass it as remittance_id wherever a call names this remittance.

object always "remittance" required

Always remittance. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

status string required
draftapprovedexecutingcompletedpartially_completedfailed
instruction_set_id string required

The id of the accepted instruction set whose figures the legs pay, from POST /v1/remittance/instruction_sets, starting with remit_authority_rail_instruction_. Retrieve it at GET /v1/remittance/instruction_sets/{instruction_set_id}.

period string optional

The month the remittance pays for, as YYYY-MM, such as 2026-09. It's the period of the instruction set it was created from.

total Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

legs array of Leg required

One leg per authority the remittance pays, each with its own state, amount and receipt. A leg runs on its own, so one authority being down never holds the others; read each to see what settled where.

11 fields of Leg
id string required

The leg's identifier, first returned in legs on the remittance from POST /v1/remittance/remittances; it never changes. Pass it as leg_id, with the remittance's id as remittance_id, to retrieve or retry the leg.

object always "remittance_leg" required

Always remittance_leg. Tells you which kind of record you are looking at, so one handler can read any response.

remittance_id string optional

The id of the remittance this leg belongs to, from POST /v1/remittance/remittances; it starts with remit_authority_rail_remittance_. Every call that names the leg names it too, at /v1/remittance/remittances/{remittance_id}/legs/{leg_id}.

authority_id string required

The id of the authority this leg pays, as listed at GET /v1/remittance/authorities; it starts with remit_authority_rail_obligation_. Look it up at GET /v1/remittance/authorities/{authority_id} for its name, tier and capabilities.

authority_name string optional

The authority's name as you'd write it, such as Rivers State Internal Revenue Service. For display; authority_id is what you match on.

tier string optional

How the filing reaches the authority. Readable so you know what to expect on timing. Never something to code against, since all three present the same contract.

direct_apiportal_automationassisted_manual
status string required

A leg reaches completed only once its receipt is vaulted. quarantined means a receipt arrived but disagreed with the leg.

pendingexecutingawaiting_receiptcompletedquarantinedfailed
amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

receipt_id string · nullable optional

The id of the receipt that is this leg's proof of payment, once vaulted; it starts with remit_authority_rail_receipt_ and you retrieve it at GET /v1/remittance/receipts/{receipt_id}. null until a receipt is vaulted.

attempts integer · minimum 0 optional

How many times filing this leg with its authority has been tried, retries included. 0 before the first try; read it with last_fault before you retry.

last_fault string · nullable optional

Why the latest attempt failed, in words for a person to read, such as The register did not answer within the timeout. null when there is no fault to report; read it before you retry.

approved_by string · nullable optional

Who approved the remittance: the actor that called approve. null while it is still draft, and execution is refused until a person is named here.

created_at string · date-time optional

When the record was created, as an RFC 3339 timestamp in UTC.

has_more boolean required

true when there are more records after this page. Pass the last record's id as starting_after to get the next page.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
# query parameters: limit (optional), starting_after (optional), status (optional)
curl -X GET "https://sandbox.droomwork.io/v1/remittance/remittances?limit=25&status=draft" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

// query parameters: limit (optional), starting_after (optional), status (optional)
const result = await api.remittanceRemittancesList({ limit: 25, status: 'draft' });
// query parameters: limit (optional), starting_after (optional), status (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/remittances?limit=25&status=draft', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

# query parameters: limit (optional), starting_after (optional), status (optional)
result = api.remittance_remittances_list(limit=25, status='draft')
import os

import requests

# query parameters: limit (optional), starting_after (optional), status (optional)
response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/remittances?limit=25&status=draft',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

# query parameters: limit (optional), starting_after (optional), status (optional)
$result = $api->remittanceRemittancesList(limit: 25, status: 'draft');
<?php
// query parameters: limit (optional), starting_after (optional), status (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/remittances?limit=25&status=draft');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;
import com.useheros.sdk.model.*;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

// query parameters: limit (optional), starting_after (optional), status (optional)
var result = api.remittanceRemittancesList(25, null, RemitRemittanceStatus.fromValue("draft"));
// query parameters: limit (optional), starting_after (optional), status (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/remittances?limit=25&status=draft"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

// query parameters: limit (optional), starting_after (optional), status (optional)
var result = api.RemittanceRemittancesList(limit: 25, status: RemitRemittanceStatus.Draft);
// query parameters: limit (optional), starting_after (optional), status (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/remittances?limit=25&status=draft");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

// query parameters: limit (optional), starting_after (optional), status (optional)
result, _, err := client.REMITAPI.RemittanceRemittancesList(ctx).Limit(25).Status(heros.RemitRemittanceStatus("draft")).Execute()
// query parameters: limit (optional), starting_after (optional), status (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/remittances?limit=25&status=draft", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "object": "list",
  "data": [
    {
      "id": "remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "object": "remittance",
      "livemode": false,
      "mocked": true,
      "status": "draft",
      "instruction_set_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "legs": [
        {
          "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
          "object": "remittance_leg",
          "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
          "status": "pending",
          "amount": {
            "amount": 7500000,
            "currency": "NGN"
          },
          "remittance_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
          "authority_name": "Sandbox State Internal Revenue Service",
          "tier": "direct_api",
          "receipt_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
          "attempts": 0,
          "last_fault": "The register did not answer within the timeout."
        }
      ],
      "total": {
        "amount": 57900000,
        "currency": "NGN"
      },
      "period": "2026-09",
      "approved_by": "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "created_at": "2026-09-01T09:00:00Z"
    }
  ],
  "has_more": true
}
POST/v1/remittance/remittances#

Open a remittance from an accepted instruction set

remittance.remittances.create

This turns figures you have accepted into the payment of them. Everything that follows hangs off the identifier it hands back, the approval, the execution and each leg's own retry, so your system keeps one string and reads each authority's state off it from then on.

Send the instruction set's id. You get the remittance back in draft, with an id starting remit_authority_rail_remittance_ to keep and its total in whole minor units with its currency across every leg.

The set has to be accepted first, at POST /v1/remittance/instruction_sets/{instruction_set_id}/accept.

One remittance pays one month, the month of the set it was created from. Another month means another accepted set.

Approve it next at POST /v1/remittance/remittances/{remittance_id}/approve, sending this id as remittance_id.

Headers

Idempotency-Key string required

A key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.

Body

instruction_set_id string required

The id of the instruction set to remit, from POST /v1/remittance/instruction_sets; it starts with remit_authority_rail_instruction_ and must be accepted first. You get one leg per authority it names, or only those in authority_ids.

authority_ids array of string optional

Defaults to every authority named in the instruction set.

Returns

The remittance, with created_at where there is one, to date your own row by.

id string required

The remittance's identifier, first returned by POST /v1/remittance/remittances; it starts with remit_authority_rail_remittance_ and never changes. Pass it as remittance_id wherever a call names this remittance.

object always "remittance" required

Always remittance. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

status string required
draftapprovedexecutingcompletedpartially_completedfailed
instruction_set_id string required

The id of the accepted instruction set whose figures the legs pay, from POST /v1/remittance/instruction_sets, starting with remit_authority_rail_instruction_. Retrieve it at GET /v1/remittance/instruction_sets/{instruction_set_id}.

period string optional

The month the remittance pays for, as YYYY-MM, such as 2026-09. It's the period of the instruction set it was created from.

total Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

legs array of Leg required

One leg per authority the remittance pays, each with its own state, amount and receipt. A leg runs on its own, so one authority being down never holds the others; read each to see what settled where.

11 fields of Leg
id string required

The leg's identifier, first returned in legs on the remittance from POST /v1/remittance/remittances; it never changes. Pass it as leg_id, with the remittance's id as remittance_id, to retrieve or retry the leg.

object always "remittance_leg" required

Always remittance_leg. Tells you which kind of record you are looking at, so one handler can read any response.

remittance_id string optional

The id of the remittance this leg belongs to, from POST /v1/remittance/remittances; it starts with remit_authority_rail_remittance_. Every call that names the leg names it too, at /v1/remittance/remittances/{remittance_id}/legs/{leg_id}.

authority_id string required

The id of the authority this leg pays, as listed at GET /v1/remittance/authorities; it starts with remit_authority_rail_obligation_. Look it up at GET /v1/remittance/authorities/{authority_id} for its name, tier and capabilities.

authority_name string optional

The authority's name as you'd write it, such as Rivers State Internal Revenue Service. For display; authority_id is what you match on.

tier string optional

How the filing reaches the authority. Readable so you know what to expect on timing. Never something to code against, since all three present the same contract.

direct_apiportal_automationassisted_manual
status string required

A leg reaches completed only once its receipt is vaulted. quarantined means a receipt arrived but disagreed with the leg.

pendingexecutingawaiting_receiptcompletedquarantinedfailed
amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

receipt_id string · nullable optional

The id of the receipt that is this leg's proof of payment, once vaulted; it starts with remit_authority_rail_receipt_ and you retrieve it at GET /v1/remittance/receipts/{receipt_id}. null until a receipt is vaulted.

attempts integer · minimum 0 optional

How many times filing this leg with its authority has been tried, retries included. 0 before the first try; read it with last_fault before you retry.

last_fault string · nullable optional

Why the latest attempt failed, in words for a person to read, such as The register did not answer within the timeout. null when there is no fault to report; read it before you retry.

approved_by string · nullable optional

Who approved the remittance: the actor that called approve. null while it is still draft, and execution is refused until a person is named here.

created_at string · date-time optional

When the record was created, as an RFC 3339 timestamp in UTC.

Other responses

400The request could not be read, or a value was refused.
401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.
409The record is not in a state that allows this.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X POST "https://sandbox.droomwork.io/v1/remittance/remittances" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"instruction_set_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","authority_ids":["sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"]}'
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceRemittancesCreate({
  idempotencyKey: crypto.randomUUID(),
  remitRemittanceCreateRequest: {"instructionSetId":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","authorityIds":["sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"]},
});
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/remittances', {
  method: 'POST',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
  },
  body: JSON.stringify({
    "instruction_set_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
    "authority_ids": [
      "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
    ]
  }),
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_remittances_create(body={"instruction_set_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "authority_ids": ["sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"]})
import os
import uuid

import requests

response = requests.request(
    'POST',
    'https://sandbox.droomwork.io/v1/remittance/remittances',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
        'Idempotency-Key': str(uuid.uuid4()),
    },
    json={"instruction_set_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "authority_ids": ["sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"]},
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceRemittancesCreate($idempotencyKey, json_decode('{"instruction_set_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","authority_ids":["sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"]}', true));
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/remittances');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
    'Content-Type: application/json',
    'Idempotency-Key: ' . bin2hex(random_bytes(16)),
  ],
  CURLOPT_POSTFIELDS => '{"instruction_set_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","authority_ids":["sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"]}',
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceRemittancesCreate(idempotencyKey, body);
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/remittances"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .header("Content-Type", "application/json")
    .header("Idempotency-Key", UUID.randomUUID().toString())
    .method("POST", HttpRequest.BodyPublishers.ofString("""
        {
          "instruction_set_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
          "authority_ids": [
            "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
          ]
        }
        """))
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceRemittancesCreate(idempotencyKey, body);
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/remittance/remittances");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
request.Content = new StringContent("""
    {
      "instruction_set_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "authority_ids": [
        "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
      ]
    }
    """, Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceRemittancesCreate(ctx).IdempotencyKey(key).RemitRemittanceCreateRequest(body).Execute()
body := strings.NewReader(`{
  "instruction_set_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "authority_ids": [
    "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
  ]
}`)
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/remittance/remittances", body)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "remittance",
  "livemode": false,
  "mocked": true,
  "status": "draft",
  "instruction_set_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "legs": [
    {
      "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "object": "remittance_leg",
      "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "status": "pending",
      "amount": {
        "amount": 7500000,
        "currency": "NGN"
      },
      "remittance_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "authority_name": "Sandbox State Internal Revenue Service",
      "tier": "direct_api",
      "receipt_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "attempts": 0,
      "last_fault": "The register did not answer within the timeout."
    }
  ],
  "total": {
    "amount": 57900000,
    "currency": "NGN"
  },
  "period": "2026-09",
  "approved_by": "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "created_at": "2026-09-01T09:00:00Z"
}
GET/v1/remittance/remittances/{remittance_id}#

Read one remittance and every leg it holds

remittance.remittances.retrieve

A remittance is one month's payment of what an accepted instruction set says you owe, split into a leg for each authority it pays. This reads one back whole, its total and every leg's amount in the same answer, so a screen in your product can show a month's filing from a single call.

Send the remittance's id in the path. You get the record as it stands: status for where the remittance has got to, and on each leg its own status, the authority it pays and what it pays them.

While it is still draft, approve it at POST /v1/remittance/remittances/{remittance_id}/approve. Read the legs on their own at GET /v1/remittance/remittances/{remittance_id}/legs.

Path parameters

remittance_id string required

The remittance's identifier: the id of a remittance you created at POST /v1/remittance/remittances or listed at GET /v1/remittance/remittances. It starts with remit_authority_rail_remittance_.

Returns

One remittance, naming the receipt behind each leg that has one, so the proof can be fetched next.

id string required

The remittance's identifier, first returned by POST /v1/remittance/remittances; it starts with remit_authority_rail_remittance_ and never changes. Pass it as remittance_id wherever a call names this remittance.

object always "remittance" required

Always remittance. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

status string required
draftapprovedexecutingcompletedpartially_completedfailed
instruction_set_id string required

The id of the accepted instruction set whose figures the legs pay, from POST /v1/remittance/instruction_sets, starting with remit_authority_rail_instruction_. Retrieve it at GET /v1/remittance/instruction_sets/{instruction_set_id}.

period string optional

The month the remittance pays for, as YYYY-MM, such as 2026-09. It's the period of the instruction set it was created from.

total Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

legs array of Leg required

One leg per authority the remittance pays, each with its own state, amount and receipt. A leg runs on its own, so one authority being down never holds the others; read each to see what settled where.

11 fields of Leg
id string required

The leg's identifier, first returned in legs on the remittance from POST /v1/remittance/remittances; it never changes. Pass it as leg_id, with the remittance's id as remittance_id, to retrieve or retry the leg.

object always "remittance_leg" required

Always remittance_leg. Tells you which kind of record you are looking at, so one handler can read any response.

remittance_id string optional

The id of the remittance this leg belongs to, from POST /v1/remittance/remittances; it starts with remit_authority_rail_remittance_. Every call that names the leg names it too, at /v1/remittance/remittances/{remittance_id}/legs/{leg_id}.

authority_id string required

The id of the authority this leg pays, as listed at GET /v1/remittance/authorities; it starts with remit_authority_rail_obligation_. Look it up at GET /v1/remittance/authorities/{authority_id} for its name, tier and capabilities.

authority_name string optional

The authority's name as you'd write it, such as Rivers State Internal Revenue Service. For display; authority_id is what you match on.

tier string optional

How the filing reaches the authority. Readable so you know what to expect on timing. Never something to code against, since all three present the same contract.

direct_apiportal_automationassisted_manual
status string required

A leg reaches completed only once its receipt is vaulted. quarantined means a receipt arrived but disagreed with the leg.

pendingexecutingawaiting_receiptcompletedquarantinedfailed
amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

receipt_id string · nullable optional

The id of the receipt that is this leg's proof of payment, once vaulted; it starts with remit_authority_rail_receipt_ and you retrieve it at GET /v1/remittance/receipts/{receipt_id}. null until a receipt is vaulted.

attempts integer · minimum 0 optional

How many times filing this leg with its authority has been tried, retries included. 0 before the first try; read it with last_fault before you retry.

last_fault string · nullable optional

Why the latest attempt failed, in words for a person to read, such as The register did not answer within the timeout. null when there is no fault to report; read it before you retry.

approved_by string · nullable optional

Who approved the remittance: the actor that called approve. null while it is still draft, and execution is refused until a person is named here.

created_at string · date-time optional

When the record was created, as an RFC 3339 timestamp in UTC.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X GET "https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceRemittancesRetrieve({ remittanceId: 'remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_remittances_retrieve(remittance_id='remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')
import os

import requests

response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceRemittancesRetrieve(remittance_id: 'remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceRemittancesRetrieve("remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceRemittancesRetrieve(remittanceId: "remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceRemittancesRetrieve(ctx, "remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "remittance",
  "livemode": false,
  "mocked": true,
  "status": "draft",
  "instruction_set_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "legs": [
    {
      "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "object": "remittance_leg",
      "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "status": "pending",
      "amount": {
        "amount": 7500000,
        "currency": "NGN"
      },
      "remittance_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "authority_name": "Sandbox State Internal Revenue Service",
      "tier": "direct_api",
      "receipt_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "attempts": 0,
      "last_fault": "The register did not answer within the timeout."
    }
  ],
  "total": {
    "amount": 57900000,
    "currency": "NGN"
  },
  "period": "2026-09",
  "approved_by": "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "created_at": "2026-09-01T09:00:00Z"
}
POST/v1/remittance/remittances/{remittance_id}/approve#

Approve a remittance for filing

remittance.remittances.approve

This is where a person agrees that a remittance should go to the authorities with the figures it holds. Approving is a call of its own, so your product can put a month's figures in front of whoever signs them off, and filing is refused until they have.

Send the remittance's id in the path and no request body. You get the whole remittance back, its total and its legs with it, and its status now approved.

The remittance has to be in draft, which is where POST /v1/remittance/remittances leaves it.

Execute it next at POST /v1/remittance/remittances/{remittance_id}/execute, which is the call that files with each authority. A remittance that has left draft is refused with conflict.

Path parameters

remittance_id string required

The remittance's identifier: the id of a remittance you created at POST /v1/remittance/remittances or listed at GET /v1/remittance/remittances. It starts with remit_authority_rail_remittance_.

Headers

Idempotency-Key string required

A key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.

Returns

The remittance, now approved and not yet executed.

id string required

The remittance's identifier, first returned by POST /v1/remittance/remittances; it starts with remit_authority_rail_remittance_ and never changes. Pass it as remittance_id wherever a call names this remittance.

object always "remittance" required

Always remittance. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

status string required
draftapprovedexecutingcompletedpartially_completedfailed
instruction_set_id string required

The id of the accepted instruction set whose figures the legs pay, from POST /v1/remittance/instruction_sets, starting with remit_authority_rail_instruction_. Retrieve it at GET /v1/remittance/instruction_sets/{instruction_set_id}.

period string optional

The month the remittance pays for, as YYYY-MM, such as 2026-09. It's the period of the instruction set it was created from.

total Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

legs array of Leg required

One leg per authority the remittance pays, each with its own state, amount and receipt. A leg runs on its own, so one authority being down never holds the others; read each to see what settled where.

11 fields of Leg
id string required

The leg's identifier, first returned in legs on the remittance from POST /v1/remittance/remittances; it never changes. Pass it as leg_id, with the remittance's id as remittance_id, to retrieve or retry the leg.

object always "remittance_leg" required

Always remittance_leg. Tells you which kind of record you are looking at, so one handler can read any response.

remittance_id string optional

The id of the remittance this leg belongs to, from POST /v1/remittance/remittances; it starts with remit_authority_rail_remittance_. Every call that names the leg names it too, at /v1/remittance/remittances/{remittance_id}/legs/{leg_id}.

authority_id string required

The id of the authority this leg pays, as listed at GET /v1/remittance/authorities; it starts with remit_authority_rail_obligation_. Look it up at GET /v1/remittance/authorities/{authority_id} for its name, tier and capabilities.

authority_name string optional

The authority's name as you'd write it, such as Rivers State Internal Revenue Service. For display; authority_id is what you match on.

tier string optional

How the filing reaches the authority. Readable so you know what to expect on timing. Never something to code against, since all three present the same contract.

direct_apiportal_automationassisted_manual
status string required

A leg reaches completed only once its receipt is vaulted. quarantined means a receipt arrived but disagreed with the leg.

pendingexecutingawaiting_receiptcompletedquarantinedfailed
amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

receipt_id string · nullable optional

The id of the receipt that is this leg's proof of payment, once vaulted; it starts with remit_authority_rail_receipt_ and you retrieve it at GET /v1/remittance/receipts/{receipt_id}. null until a receipt is vaulted.

attempts integer · minimum 0 optional

How many times filing this leg with its authority has been tried, retries included. 0 before the first try; read it with last_fault before you retry.

last_fault string · nullable optional

Why the latest attempt failed, in words for a person to read, such as The register did not answer within the timeout. null when there is no fault to report; read it before you retry.

approved_by string · nullable optional

Who approved the remittance: the actor that called approve. null while it is still draft, and execution is refused until a person is named here.

created_at string · date-time optional

When the record was created, as an RFC 3339 timestamp in UTC.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.
409The record is not in a state that allows this.
422A required fact is missing. Call the readiness endpoint to see what.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X POST "https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/approve" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceRemittancesApprove({ remittanceId: 'remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/approve', {
  method: 'POST',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
    'Idempotency-Key': crypto.randomUUID(),
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_remittances_approve(remittance_id='remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')
import os
import uuid

import requests

response = requests.request(
    'POST',
    'https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/approve',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
        'Idempotency-Key': str(uuid.uuid4()),
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceRemittancesApprove(remittance_id: 'remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/approve');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
    'Idempotency-Key: ' . bin2hex(random_bytes(16)),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceRemittancesApprove("remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/approve"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .header("Idempotency-Key", UUID.randomUUID().toString())
    .method("POST", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceRemittancesApprove(remittanceId: "remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/approve");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceRemittancesApprove(ctx, "remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/approve", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "remittance",
  "livemode": false,
  "mocked": true,
  "status": "approved",
  "instruction_set_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "legs": [
    {
      "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "object": "remittance_leg",
      "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "status": "pending",
      "amount": {
        "amount": 7500000,
        "currency": "NGN"
      },
      "remittance_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "authority_name": "Sandbox State Internal Revenue Service",
      "tier": "direct_api",
      "receipt_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "attempts": 0,
      "last_fault": "The register did not answer within the timeout."
    }
  ],
  "total": {
    "amount": 57900000,
    "currency": "NGN"
  },
  "period": "2026-09",
  "approved_by": "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "created_at": "2026-09-01T09:00:00Z"
}
GET/v1/remittance/remittances/{remittance_id}/legs#

See each authority's part of a remittance

remittance.legs.list

This reads all of one remittance's legs in a single answer. Your product can then work a queue of only the legs that failed, without reading a whole remittance to find them.

Send the remittance's id in the path. Each leg you get back carries the authority_id it pays, a status, an amount in whole minor units with its currency, and last_fault when an attempt has left one.

Read one leg in full at GET /v1/remittance/remittances/{remittance_id}/legs/{leg_id}, and retry that leg at POST /v1/remittance/remittances/{remittance_id}/legs/{leg_id}/retry when its status is failed. An unknown remittance_id answers not_found.

Path parameters

remittance_id string required

The remittance's identifier: the id of a remittance you created at POST /v1/remittance/remittances or listed at GET /v1/remittance/remittances. It starts with remit_authority_rail_remittance_.

Query parameters

limit integer optional

How many records to return on one page, from 1 to 100, and 25 if you leave it out. When has_more is true, pass the last record's id as starting_after to get the next page.

status string optional

Return only legs in one state: pending (not yet executed), executing, awaiting_receipt (filed), completed (receipt vaulted), quarantined (receipt disagreed with the leg) or failed (needs a retry). Leave it out to get every state.

pendingexecutingawaiting_receiptcompletedquarantinedfailed

Returns

One row for each leg, with how each filing reaches its authority, so a slow one is no surprise.

object always "list" required

Always list. Tells you which kind of record you are looking at, so one handler can read any response.

data array of Leg required

The records on this page, in the order the list promises. Empty when nothing matched.

11 fields of Leg
id string required

The leg's identifier, first returned in legs on the remittance from POST /v1/remittance/remittances; it never changes. Pass it as leg_id, with the remittance's id as remittance_id, to retrieve or retry the leg.

object always "remittance_leg" required

Always remittance_leg. Tells you which kind of record you are looking at, so one handler can read any response.

remittance_id string optional

The id of the remittance this leg belongs to, from POST /v1/remittance/remittances; it starts with remit_authority_rail_remittance_. Every call that names the leg names it too, at /v1/remittance/remittances/{remittance_id}/legs/{leg_id}.

authority_id string required

The id of the authority this leg pays, as listed at GET /v1/remittance/authorities; it starts with remit_authority_rail_obligation_. Look it up at GET /v1/remittance/authorities/{authority_id} for its name, tier and capabilities.

authority_name string optional

The authority's name as you'd write it, such as Rivers State Internal Revenue Service. For display; authority_id is what you match on.

tier string optional

How the filing reaches the authority. Readable so you know what to expect on timing. Never something to code against, since all three present the same contract.

direct_apiportal_automationassisted_manual
status string required

A leg reaches completed only once its receipt is vaulted. quarantined means a receipt arrived but disagreed with the leg.

pendingexecutingawaiting_receiptcompletedquarantinedfailed
amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

receipt_id string · nullable optional

The id of the receipt that is this leg's proof of payment, once vaulted; it starts with remit_authority_rail_receipt_ and you retrieve it at GET /v1/remittance/receipts/{receipt_id}. null until a receipt is vaulted.

attempts integer · minimum 0 optional

How many times filing this leg with its authority has been tried, retries included. 0 before the first try; read it with last_fault before you retry.

last_fault string · nullable optional

Why the latest attempt failed, in words for a person to read, such as The register did not answer within the timeout. null when there is no fault to report; read it before you retry.

has_more boolean required

true when there are more records after this page. Pass the last record's id as starting_after to get the next page.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
# query parameters: limit (optional), status (optional)
curl -X GET "https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs?limit=25&status=pending" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

// query parameters: limit (optional), status (optional)
const result = await api.remittanceLegsList({ remittanceId: 'remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', limit: 25, status: 'pending' });
// query parameters: limit (optional), status (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs?limit=25&status=pending', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

# query parameters: limit (optional), status (optional)
result = api.remittance_legs_list(remittance_id='remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', limit=25, status='pending')
import os

import requests

# query parameters: limit (optional), status (optional)
response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs?limit=25&status=pending',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

# query parameters: limit (optional), status (optional)
$result = $api->remittanceLegsList(remittance_id: 'remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', limit: 25, status: 'pending');
<?php
// query parameters: limit (optional), status (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs?limit=25&status=pending');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;
import com.useheros.sdk.model.*;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

// query parameters: limit (optional), status (optional)
var result = api.remittanceLegsList("remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", 25, RemitLegStatus.fromValue("pending"));
// query parameters: limit (optional), status (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs?limit=25&status=pending"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

// query parameters: limit (optional), status (optional)
var result = api.RemittanceLegsList(remittanceId: "remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", limit: 25, status: RemitLegStatus.Pending);
// query parameters: limit (optional), status (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs?limit=25&status=pending");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

// query parameters: limit (optional), status (optional)
result, _, err := client.REMITAPI.RemittanceLegsList(ctx, "remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Limit(25).Status(heros.RemitLegStatus("pending")).Execute()
// query parameters: limit (optional), status (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs?limit=25&status=pending", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "object": "list",
  "data": [
    {
      "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "object": "remittance_leg",
      "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "status": "pending",
      "amount": {
        "amount": 7500000,
        "currency": "NGN"
      },
      "remittance_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "authority_name": "Sandbox State Internal Revenue Service",
      "tier": "direct_api",
      "receipt_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "attempts": 0,
      "last_fault": "The register did not answer within the timeout."
    }
  ],
  "has_more": true
}
GET/v1/remittance/remittances/{remittance_id}/legs/{leg_id}#

Check where one leg has got to

remittance.legs.retrieve

A leg is one authority's part of a remittance, with its own state, amount and receipt. This reads one back on its own, so your product can follow a single authority's filing, and show the fault behind its last attempt, without reading the whole remittance again.

Send the remittance's id and the leg's id in the path. You get that leg: status for how far its filing has got, amount for what it pays, tier for how the filing reaches the authority, and last_fault for why the latest attempt failed.

Where the leg carries a receipt_id, read that receipt at GET /v1/remittance/receipts/{receipt_id}. See the remittance's legs together at GET /v1/remittance/remittances/{remittance_id}/legs. A leg_id from another remittance answers not_found.

Path parameters

remittance_id string required

The remittance's identifier: the id of a remittance you created at POST /v1/remittance/remittances or listed at GET /v1/remittance/remittances. It starts with remit_authority_rail_remittance_.

leg_id string required

The leg's identifier: the id of a leg in legs on the remittance from POST /v1/remittance/remittances, or listed at GET /v1/remittance/remittances/{remittance_id}/legs. It belongs to the remittance in the path.

Returns

One leg in full, with the count of tries behind it, enough to judge whether another is worth it.

id string required

The leg's identifier, first returned in legs on the remittance from POST /v1/remittance/remittances; it never changes. Pass it as leg_id, with the remittance's id as remittance_id, to retrieve or retry the leg.

object always "remittance_leg" required

Always remittance_leg. Tells you which kind of record you are looking at, so one handler can read any response.

remittance_id string optional

The id of the remittance this leg belongs to, from POST /v1/remittance/remittances; it starts with remit_authority_rail_remittance_. Every call that names the leg names it too, at /v1/remittance/remittances/{remittance_id}/legs/{leg_id}.

authority_id string required

The id of the authority this leg pays, as listed at GET /v1/remittance/authorities; it starts with remit_authority_rail_obligation_. Look it up at GET /v1/remittance/authorities/{authority_id} for its name, tier and capabilities.

authority_name string optional

The authority's name as you'd write it, such as Rivers State Internal Revenue Service. For display; authority_id is what you match on.

tier string optional

How the filing reaches the authority. Readable so you know what to expect on timing. Never something to code against, since all three present the same contract.

direct_apiportal_automationassisted_manual
status string required

A leg reaches completed only once its receipt is vaulted. quarantined means a receipt arrived but disagreed with the leg.

pendingexecutingawaiting_receiptcompletedquarantinedfailed
amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

receipt_id string · nullable optional

The id of the receipt that is this leg's proof of payment, once vaulted; it starts with remit_authority_rail_receipt_ and you retrieve it at GET /v1/remittance/receipts/{receipt_id}. null until a receipt is vaulted.

attempts integer · minimum 0 optional

How many times filing this leg with its authority has been tried, retries included. 0 before the first try; read it with last_fault before you retry.

last_fault string · nullable optional

Why the latest attempt failed, in words for a person to read, such as The register did not answer within the timeout. null when there is no fault to report; read it before you retry.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X GET "https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs/%7Bleg_id%7D" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceLegsRetrieve({ remittanceId: 'remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', legId: '{leg_id}' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs/%7Bleg_id%7D', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_legs_retrieve(remittance_id='remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', leg_id='{leg_id}')
import os

import requests

response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs/%7Bleg_id%7D',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceLegsRetrieve(remittance_id: 'remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', leg_id: '{leg_id}');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs/%7Bleg_id%7D');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceLegsRetrieve("remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "{leg_id}");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs/%7Bleg_id%7D"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceLegsRetrieve(remittanceId: "remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", legId: "{leg_id}");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs/%7Bleg_id%7D");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceLegsRetrieve(ctx, "remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "{leg_id}").Execute()
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs/%7Bleg_id%7D", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "remittance_leg",
  "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "status": "pending",
  "amount": {
    "amount": 7500000,
    "currency": "NGN"
  },
  "remittance_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "authority_name": "Sandbox State Internal Revenue Service",
  "tier": "direct_api",
  "receipt_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "attempts": 0,
  "last_fault": "The register did not answer within the timeout."
}
POST/v1/remittance/remittances/{remittance_id}/legs/{leg_id}/retry#

Retry a failed leg

remittance.legs.retry

A leg that came back failed is one authority's filing left undone. This retries that one leg, so a single authority's failure does not mean re-running a remittance you have already executed.

Send the remittance's id and the leg's id in the path. Send no request body. You get the leg back with its status set to pending, accepted for another attempt and not yet filed.

The remittance has to exist, from POST /v1/remittance/remittances, and the leg has to be one listed at GET /v1/remittance/remittances/{remittance_id}/legs.

Read the leg again at GET /v1/remittance/remittances/{remittance_id}/legs/{leg_id} for its state and its last_fault. An unknown remittance_id, or a leg_id from another remittance, answers not_found.

Path parameters

remittance_id string required

The remittance's identifier: the id of a remittance you created at POST /v1/remittance/remittances or listed at GET /v1/remittance/remittances. It starts with remit_authority_rail_remittance_.

leg_id string required

The leg's identifier: the id of a leg in legs on the remittance from POST /v1/remittance/remittances, or listed at GET /v1/remittance/remittances/{remittance_id}/legs. It belongs to the remittance in the path.

Headers

Idempotency-Key string required

A key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.

Returns

The leg itself, still carrying the fault behind the previous attempt, so a repeat is recognisable.

id string required

The leg's identifier, first returned in legs on the remittance from POST /v1/remittance/remittances; it never changes. Pass it as leg_id, with the remittance's id as remittance_id, to retrieve or retry the leg.

object always "remittance_leg" required

Always remittance_leg. Tells you which kind of record you are looking at, so one handler can read any response.

remittance_id string optional

The id of the remittance this leg belongs to, from POST /v1/remittance/remittances; it starts with remit_authority_rail_remittance_. Every call that names the leg names it too, at /v1/remittance/remittances/{remittance_id}/legs/{leg_id}.

authority_id string required

The id of the authority this leg pays, as listed at GET /v1/remittance/authorities; it starts with remit_authority_rail_obligation_. Look it up at GET /v1/remittance/authorities/{authority_id} for its name, tier and capabilities.

authority_name string optional

The authority's name as you'd write it, such as Rivers State Internal Revenue Service. For display; authority_id is what you match on.

tier string optional

How the filing reaches the authority. Readable so you know what to expect on timing. Never something to code against, since all three present the same contract.

direct_apiportal_automationassisted_manual
status string required

A leg reaches completed only once its receipt is vaulted. quarantined means a receipt arrived but disagreed with the leg.

pendingexecutingawaiting_receiptcompletedquarantinedfailed
amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

receipt_id string · nullable optional

The id of the receipt that is this leg's proof of payment, once vaulted; it starts with remit_authority_rail_receipt_ and you retrieve it at GET /v1/remittance/receipts/{receipt_id}. null until a receipt is vaulted.

attempts integer · minimum 0 optional

How many times filing this leg with its authority has been tried, retries included. 0 before the first try; read it with last_fault before you retry.

last_fault string · nullable optional

Why the latest attempt failed, in words for a person to read, such as The register did not answer within the timeout. null when there is no fault to report; read it before you retry.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.
409The record is not in a state that allows this.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X POST "https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs/%7Bleg_id%7D/retry" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceLegsRetry({ remittanceId: 'remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', legId: '{leg_id}' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs/%7Bleg_id%7D/retry', {
  method: 'POST',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
    'Idempotency-Key': crypto.randomUUID(),
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_legs_retry(remittance_id='remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', leg_id='{leg_id}')
import os
import uuid

import requests

response = requests.request(
    'POST',
    'https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs/%7Bleg_id%7D/retry',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
        'Idempotency-Key': str(uuid.uuid4()),
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceLegsRetry(remittance_id: 'remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', leg_id: '{leg_id}');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs/%7Bleg_id%7D/retry');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
    'Idempotency-Key: ' . bin2hex(random_bytes(16)),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceLegsRetry("remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "{leg_id}");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs/%7Bleg_id%7D/retry"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .header("Idempotency-Key", UUID.randomUUID().toString())
    .method("POST", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceLegsRetry(remittanceId: "remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", legId: "{leg_id}");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs/%7Bleg_id%7D/retry");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceLegsRetry(ctx, "remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "{leg_id}").Execute()
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/legs/%7Bleg_id%7D/retry", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "remittance_leg",
  "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "status": "pending",
  "amount": {
    "amount": 7500000,
    "currency": "NGN"
  },
  "remittance_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "authority_name": "Sandbox State Internal Revenue Service",
  "tier": "direct_api",
  "receipt_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "attempts": 0,
  "last_fault": "The register did not answer within the timeout."
}
GET/v1/remittance/receipts#

What proof of payment you hold

remittance.receipts.list

A receipt is one authority's acknowledgement that money reached it, for one month, under the reference that authority itself issued. So your own system can show that an authority acknowledged a payment, which a filing reported as successful does not prove on its own.

You get one row per receipt, with its id, the authority and period it covers, the amount acknowledged, and what kind of proof it is. The document itself, where there is one, is a URL on the row.

Read one on its own at GET /v1/remittance/receipts/{receipt_id}, passing its id as receipt_id.

Query parameters

limit integer optional

How many records to return on one page, from 1 to 100, and 25 if you leave it out. When has_more is true, pass the last record's id as starting_after to get the next page.

starting_after string optional

The id of the last record on the previous page of this same list. Leave it out to get the first page; when a page comes back with has_more true, send its last record's id here to get the page after it.

authority_id string optional

Return only receipts issued by one authority: its id from GET /v1/remittance/authorities, or the authority_id on a leg or obligation, starting with remit_authority_rail_obligation_. Leave it out to get every authority.

period string optional

Return only receipts whose payment covers one month, as YYYY-MM, such as 2026-09: the period each receipt carries. Leave it out to get every period.

Returns

A page of receipts, each carrying the hash that fixes its place in the chain.

object always "list" required

Always list. Tells you which kind of record you are looking at, so one handler can read any response.

data array of Receipt required

The records on this page, in the order the list promises. Empty when nothing matched.

17 fields of Receipt
id string required

The receipt's identifier, starting with remit_authority_rail_receipt_; it never changes. It is the receipt_id on the leg it proves and in receipt_ids on its obligation; pass it as receipt_id to GET /v1/remittance/receipts/{receipt_id}.

object always "remittance_receipt" required

Always remittance_receipt. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

leg_id string · nullable optional

The id of the leg this receipt proves paid, from legs on a remittance or GET /v1/remittance/remittances/{remittance_id}/legs; vaulting the receipt takes that leg to completed. null when the receipt is not tied to a leg.

obligation_id string · nullable optional

The id of the obligation this receipt settles against, from GET /v1/remittance/obligations, starting with remit_authority_rail_obligation_; the receipt also appears in its receipt_ids. null when not tied to an obligation.

authority_id string required

The id of the authority that issued this receipt, from GET /v1/remittance/authorities, starting with remit_authority_rail_obligation_; filter the list by it. It must agree with the leg's authority_id, or the receipt is quarantined.

period string required

The month the payment covers, as YYYY-MM, such as 2026-09; filter the list by it with the period query. It must agree with the leg's period, or the receipt is quarantined.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

authority_reference string optional

The reference the authority itself issued.

evidence_class string required

The same classes apply whichever tier filed. An assisted manual filing carries a receipt reference, a document scan and an operator attestation under dual control, which is the same evidence class as an API filing.

authority_api_receiptportal_receiptassisted_manual_attested
document_url string · uri · nullable optional

Where to fetch the receipt document the authority issued, as a URL. Present for an assisted manual filing, where you supplied the scan; null when there is no document.

hash string required

This receipt position in the append only chain.

previous_hash string required

The hash of the receipt vaulted just before this one. Each receipt carries the last one's hash, so you can walk the chain back and confirm nothing was changed or removed.

trace_references array of string optional

The payroll trace references this receipt covers.

attested_by array of string optional

Two actors for an assisted manual filing, under dual control.

vaulted_at string · date-time optional

When the receipt was hash chained into the vault, as an RFC 3339 timestamp in UTC. From this moment it never changes, and the leg it belongs to can reach completed.

has_more boolean required

true when there are more records after this page. Pass the last record's id as starting_after to get the next page.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
# query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional)
curl -X GET "https://sandbox.droomwork.io/v1/remittance/receipts?limit=25&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&period=2026-09" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

// query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional)
const result = await api.remittanceReceiptsList({ limit: 25, authorityId: 'remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', period: '2026-09' });
// query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/receipts?limit=25&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&period=2026-09', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

# query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional)
result = api.remittance_receipts_list(limit=25, authority_id='remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', period='2026-09')
import os

import requests

# query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional)
response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/receipts?limit=25&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&period=2026-09',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

# query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional)
$result = $api->remittanceReceiptsList(limit: 25, authority_id: 'remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', period: '2026-09');
<?php
// query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/receipts?limit=25&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&period=2026-09');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

// query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional)
var result = api.remittanceReceiptsList(25, null, "remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "2026-09");
// query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/receipts?limit=25&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&period=2026-09"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

// query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional)
var result = api.RemittanceReceiptsList(limit: 25, authorityId: "remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", period: "2026-09");
// query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/receipts?limit=25&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&period=2026-09");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

// query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional)
result, _, err := client.REMITAPI.RemittanceReceiptsList(ctx).Limit(25).AuthorityId("remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Period("2026-09").Execute()
// query parameters: limit (optional), starting_after (optional), authority_id (optional), period (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/receipts?limit=25&authority_id=remit_authority_rail_obligation_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&period=2026-09", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "object": "list",
  "data": [
    {
      "id": "remit_authority_rail_receipt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "object": "remittance_receipt",
      "livemode": false,
      "mocked": true,
      "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "amount": {
        "amount": 7500000,
        "currency": "NGN"
      },
      "period": "2026-09",
      "evidence_class": "authority_api_receipt",
      "hash": "sha256:9f2c1e0043a1b8",
      "previous_hash": "sha256:9f2c1e0043a1b8",
      "leg_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "obligation_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "authority_reference": "paye-2026-09-rivers",
      "document_url": "https://files.sandbox.droomwork.com/example",
      "trace_references": [
        "paye-2026-09-rivers"
      ],
      "attested_by": [
        "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
      ],
      "vaulted_at": "2026-09-01T09:00:00Z"
    }
  ],
  "has_more": true
}
POST/v1/remittance/receipts#

Record a receipt from an assisted manual filing

remittance.receipts.create

Some authorities have no machine interface, so a person files with them and the authority hands back its own receipt. This is how that receipt becomes a record in the vault, the document kept beside the figures. So a hand filing stands as proof of payment in its own right, beside the receipts an authority's own system returned.

Send the leg_id you filed, the authority's reference, the amount it acknowledged, a link to your scan and two actors in attested_by. You get the vaulted receipt, its id starting remit_authority_rail_receipt_.

You need the leg you filed by hand, one of the legs on a remittance from POST /v1/remittance/remittances.

Line up two people before you call: attested_by needs two different actors, and one credential is not enough.

Keep the id; GET /v1/remittance/receipts/{receipt_id} reads it back.

Headers

Idempotency-Key string required

A key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.

Body

leg_id string required

The id of the leg you filed by hand, from legs on the remittance or GET /v1/remittance/remittances/{remittance_id}/legs: one whose authority has no machine interface. The receipt is vaulted against it, which takes the leg to completed.

authority_reference string required

The reference the authority put on its receipt, exactly as issued, such as paye-2026-09-rivers. It comes back as authority_reference on the vaulted receipt.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

document_url string · uri required

A scan of the receipt the authority issued.

attested_by array of string required

Two distinct actors. Dual control, so one credential is not enough.

Returns

The vaulted receipt, with the payroll traces it covers, so each figure reaches its proof.

id string required

The receipt's identifier, starting with remit_authority_rail_receipt_; it never changes. It is the receipt_id on the leg it proves and in receipt_ids on its obligation; pass it as receipt_id to GET /v1/remittance/receipts/{receipt_id}.

object always "remittance_receipt" required

Always remittance_receipt. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

leg_id string · nullable optional

The id of the leg this receipt proves paid, from legs on a remittance or GET /v1/remittance/remittances/{remittance_id}/legs; vaulting the receipt takes that leg to completed. null when the receipt is not tied to a leg.

obligation_id string · nullable optional

The id of the obligation this receipt settles against, from GET /v1/remittance/obligations, starting with remit_authority_rail_obligation_; the receipt also appears in its receipt_ids. null when not tied to an obligation.

authority_id string required

The id of the authority that issued this receipt, from GET /v1/remittance/authorities, starting with remit_authority_rail_obligation_; filter the list by it. It must agree with the leg's authority_id, or the receipt is quarantined.

period string required

The month the payment covers, as YYYY-MM, such as 2026-09; filter the list by it with the period query. It must agree with the leg's period, or the receipt is quarantined.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

authority_reference string optional

The reference the authority itself issued.

evidence_class string required

The same classes apply whichever tier filed. An assisted manual filing carries a receipt reference, a document scan and an operator attestation under dual control, which is the same evidence class as an API filing.

authority_api_receiptportal_receiptassisted_manual_attested
document_url string · uri · nullable optional

Where to fetch the receipt document the authority issued, as a URL. Present for an assisted manual filing, where you supplied the scan; null when there is no document.

hash string required

This receipt position in the append only chain.

previous_hash string required

The hash of the receipt vaulted just before this one. Each receipt carries the last one's hash, so you can walk the chain back and confirm nothing was changed or removed.

trace_references array of string optional

The payroll trace references this receipt covers.

attested_by array of string optional

Two actors for an assisted manual filing, under dual control.

vaulted_at string · date-time optional

When the receipt was hash chained into the vault, as an RFC 3339 timestamp in UTC. From this moment it never changes, and the leg it belongs to can reach completed.

Other responses

400The request could not be read, or a value was refused.
401No valid credential was presented.
403The credential does not carry the required scope.
409The record is not in a state that allows this.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X POST "https://sandbox.droomwork.io/v1/remittance/receipts" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"leg_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","authority_reference":"paye-2026-09-rivers","amount":{"amount":7500000,"currency":"NGN"},"document_url":"https://files.sandbox.droomwork.com/example","attested_by":["usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"]}'
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceReceiptsCreate({
  idempotencyKey: crypto.randomUUID(),
  remitReceiptCreateRequest: {"legId":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","authorityReference":"paye-2026-09-rivers","amount":{"amount":7500000,"currency":"NGN"},"documentUrl":"https://files.sandbox.droomwork.com/example","attestedBy":["usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"]},
});
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/receipts', {
  method: 'POST',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
  },
  body: JSON.stringify({
    "leg_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
    "authority_reference": "paye-2026-09-rivers",
    "amount": {
      "amount": 7500000,
      "currency": "NGN"
    },
    "document_url": "https://files.sandbox.droomwork.com/example",
    "attested_by": [
      "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
    ]
  }),
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_receipts_create(body={"leg_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "authority_reference": "paye-2026-09-rivers", "amount": {"amount": 7500000, "currency": "NGN"}, "document_url": "https://files.sandbox.droomwork.com/example", "attested_by": ["usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"]})
import os
import uuid

import requests

response = requests.request(
    'POST',
    'https://sandbox.droomwork.io/v1/remittance/receipts',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
        'Idempotency-Key': str(uuid.uuid4()),
    },
    json={"leg_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "authority_reference": "paye-2026-09-rivers", "amount": {"amount": 7500000, "currency": "NGN"}, "document_url": "https://files.sandbox.droomwork.com/example", "attested_by": ["usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"]},
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceReceiptsCreate($idempotencyKey, json_decode('{"leg_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","authority_reference":"paye-2026-09-rivers","amount":{"amount":7500000,"currency":"NGN"},"document_url":"https://files.sandbox.droomwork.com/example","attested_by":["usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"]}', true));
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/receipts');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
    'Content-Type: application/json',
    'Idempotency-Key: ' . bin2hex(random_bytes(16)),
  ],
  CURLOPT_POSTFIELDS => '{"leg_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","authority_reference":"paye-2026-09-rivers","amount":{"amount":7500000,"currency":"NGN"},"document_url":"https://files.sandbox.droomwork.com/example","attested_by":["usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"]}',
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceReceiptsCreate(idempotencyKey, body);
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/receipts"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .header("Content-Type", "application/json")
    .header("Idempotency-Key", UUID.randomUUID().toString())
    .method("POST", HttpRequest.BodyPublishers.ofString("""
        {
          "leg_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
          "authority_reference": "paye-2026-09-rivers",
          "amount": {
            "amount": 7500000,
            "currency": "NGN"
          },
          "document_url": "https://files.sandbox.droomwork.com/example",
          "attested_by": [
            "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
            "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
          ]
        }
        """))
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceReceiptsCreate(idempotencyKey, body);
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/remittance/receipts");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
request.Content = new StringContent("""
    {
      "leg_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "authority_reference": "paye-2026-09-rivers",
      "amount": {
        "amount": 7500000,
        "currency": "NGN"
      },
      "document_url": "https://files.sandbox.droomwork.com/example",
      "attested_by": [
        "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
        "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
      ]
    }
    """, Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceReceiptsCreate(ctx).IdempotencyKey(key).RemitReceiptCreateRequest(body).Execute()
body := strings.NewReader(`{
  "leg_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "authority_reference": "paye-2026-09-rivers",
  "amount": {
    "amount": 7500000,
    "currency": "NGN"
  },
  "document_url": "https://files.sandbox.droomwork.com/example",
  "attested_by": [
    "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
    "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
  ]
}`)
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/remittance/receipts", body)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_receipt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "remittance_receipt",
  "livemode": false,
  "mocked": true,
  "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "amount": {
    "amount": 7500000,
    "currency": "NGN"
  },
  "period": "2026-09",
  "evidence_class": "authority_api_receipt",
  "hash": "sha256:9f2c1e0043a1b8",
  "previous_hash": "sha256:9f2c1e0043a1b8",
  "leg_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "obligation_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "authority_reference": "paye-2026-09-rivers",
  "document_url": "https://files.sandbox.droomwork.com/example",
  "trace_references": [
    "paye-2026-09-rivers"
  ],
  "attested_by": [
    "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
  ],
  "vaulted_at": "2026-09-01T09:00:00Z"
}
GET/v1/remittance/receipts/{receipt_id}#

Open one receipt in the vault

remittance.receipts.retrieve

A receipt is what an authority gives back when money reaches it. So an identifier you stored once is all you need to pull up a single payment's proof long after the month it covers.

Send the receipt's id in the path as receipt_id. You get the amount acknowledged, the month that payment covers, what kind of proof it is, and a link to the document where there is one.

Nothing changes a receipt once it is vaulted and nothing deletes one, so the id you hold reads the same record back whenever you ask. A receipt_id nothing holds answers not_found.

Path parameters

receipt_id string required

The receipt's identifier: the id of a receipt listed at GET /v1/remittance/receipts or recorded at POST /v1/remittance/receipts, or the receipt_id on a leg. It starts with remit_authority_rail_receipt_.

Returns

The receipt, with the hash that fixes its place in the vault, to keep beside your own copy.

id string required

The receipt's identifier, starting with remit_authority_rail_receipt_; it never changes. It is the receipt_id on the leg it proves and in receipt_ids on its obligation; pass it as receipt_id to GET /v1/remittance/receipts/{receipt_id}.

object always "remittance_receipt" required

Always remittance_receipt. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

leg_id string · nullable optional

The id of the leg this receipt proves paid, from legs on a remittance or GET /v1/remittance/remittances/{remittance_id}/legs; vaulting the receipt takes that leg to completed. null when the receipt is not tied to a leg.

obligation_id string · nullable optional

The id of the obligation this receipt settles against, from GET /v1/remittance/obligations, starting with remit_authority_rail_obligation_; the receipt also appears in its receipt_ids. null when not tied to an obligation.

authority_id string required

The id of the authority that issued this receipt, from GET /v1/remittance/authorities, starting with remit_authority_rail_obligation_; filter the list by it. It must agree with the leg's authority_id, or the receipt is quarantined.

period string required

The month the payment covers, as YYYY-MM, such as 2026-09; filter the list by it with the period query. It must agree with the leg's period, or the receipt is quarantined.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

authority_reference string optional

The reference the authority itself issued.

evidence_class string required

The same classes apply whichever tier filed. An assisted manual filing carries a receipt reference, a document scan and an operator attestation under dual control, which is the same evidence class as an API filing.

authority_api_receiptportal_receiptassisted_manual_attested
document_url string · uri · nullable optional

Where to fetch the receipt document the authority issued, as a URL. Present for an assisted manual filing, where you supplied the scan; null when there is no document.

hash string required

This receipt position in the append only chain.

previous_hash string required

The hash of the receipt vaulted just before this one. Each receipt carries the last one's hash, so you can walk the chain back and confirm nothing was changed or removed.

trace_references array of string optional

The payroll trace references this receipt covers.

attested_by array of string optional

Two actors for an assisted manual filing, under dual control.

vaulted_at string · date-time optional

When the receipt was hash chained into the vault, as an RFC 3339 timestamp in UTC. From this moment it never changes, and the leg it belongs to can reach completed.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X GET "https://sandbox.droomwork.io/v1/remittance/receipts/remit_authority_rail_receipt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceReceiptsRetrieve({ receiptId: 'remit_authority_rail_receipt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/receipts/remit_authority_rail_receipt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_receipts_retrieve(receipt_id='remit_authority_rail_receipt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')
import os

import requests

response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/receipts/remit_authority_rail_receipt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceReceiptsRetrieve(receipt_id: 'remit_authority_rail_receipt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/receipts/remit_authority_rail_receipt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceReceiptsRetrieve("remit_authority_rail_receipt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/receipts/remit_authority_rail_receipt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceReceiptsRetrieve(receiptId: "remit_authority_rail_receipt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/receipts/remit_authority_rail_receipt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceReceiptsRetrieve(ctx, "remit_authority_rail_receipt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/receipts/remit_authority_rail_receipt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_receipt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "remittance_receipt",
  "livemode": false,
  "mocked": true,
  "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "amount": {
    "amount": 7500000,
    "currency": "NGN"
  },
  "period": "2026-09",
  "evidence_class": "authority_api_receipt",
  "hash": "sha256:9f2c1e0043a1b8",
  "previous_hash": "sha256:9f2c1e0043a1b8",
  "leg_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "obligation_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "authority_reference": "paye-2026-09-rivers",
  "document_url": "https://files.sandbox.droomwork.com/example",
  "trace_references": [
    "paye-2026-09-rivers"
  ],
  "attested_by": [
    "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
  ],
  "vaulted_at": "2026-09-01T09:00:00Z"
}
POST/v1/remittance/audit_exports#

Bundle the receipts you hold into one file

remittance.audit_exports.create

This gathers the receipts you hold for one month, one authority or one employee into a single pack. So passing on a period's proof is one call and one file, not a folder of receipts you gathered yourself.

Send the scope you want covered. You get the pack back with an id starting remit_authority_rail_return_, its status, and, where there is one, a download_url to fetch the file from.

Nothing has to exist first.

Carry the id as audit_export_id to GET /v1/remittance/audit_exports/{audit_export_id}. No call lists your packs, so the id is the only way back to one.

Headers

Idempotency-Key string required

A key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.

Body

period string optional

Scope the pack to one month, as YYYY-MM, such as 2026-09: every receipt for that period goes in. Send this, authority_id or subject_id, and only one of them.

authority_id string optional

Scope the pack to one authority, by its id from GET /v1/remittance/authorities, starting with remit_authority_rail_obligation_: every receipt filed with it goes in. Send this, period or subject_id, and only one of them.

subject_id string optional

Scope the pack to one employee, by their subject identifier starting with sub_, the subject_id on their payslips at GET /v1/payroll/payslips: every receipt covering them goes in. Send this, period or authority_id, and only one of them.

Returns

The export.

id string required

The pack's identifier, first returned by POST /v1/remittance/audit_exports; it starts with remit_authority_rail_return_ and never changes. Pass it as audit_export_id to GET /v1/remittance/audit_exports/{audit_export_id} to poll the pack.

object always "audit_export" required

Always audit_export. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

status string required

generating while the pack is being built, ready once it can be downloaded and verified, failed when it could not be produced. Poll GET /v1/remittance/audit_exports/{audit_export_id} until it leaves generating.

generatingreadyfailed
scope object required

What the pack covers, as the one scope you named when you asked for it: a period, an authority_id or a subject_id. The other two are null.

3 fields
period string · nullable optional

The month the pack covers, as YYYY-MM, when you scoped it by period. null when you scoped it by authority or by employee.

authority_id string · nullable optional

The authority the pack covers, when you scoped it by authority: the authority_id you sent to POST /v1/remittance/audit_exports, an id from GET /v1/remittance/authorities. null when you scoped it by period or by employee.

subject_id string · nullable optional

The employee the pack covers, when you scoped it by employee: the subject_id you sent to POST /v1/remittance/audit_exports, their subject identifier starting with sub_. null when you scoped it by period or by authority.

download_url string · uri · nullable optional

Where to fetch the pack, as a URL, once status is ready; null before then and when the pack failed. Verify what you download against signature.

signature string · nullable optional

Verify the pack against this without trusting the system that made it.

verification_instructions_url string · uri · nullable optional

Where to read how to check the pack against its signature, as a URL; null until the pack is ready. Hand it on with the pack, so whoever receives it can verify it without trusting where it came from.

receipt_count integer optional

How many vaulted receipts the pack holds for the scope you named. Compare it with your own count before you send the pack on; 0 means nothing was vaulted in that scope.

Other responses

400The request could not be read, or a value was refused.
401No valid credential was presented.
403The credential does not carry the required scope.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X POST "https://sandbox.droomwork.io/v1/remittance/audit_exports" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"period":"2026-09","authority_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","subject_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"}'
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceAuditExportsCreate({
  idempotencyKey: crypto.randomUUID(),
  remitAuditExportCreateRequest: {"period":"2026-09","authorityId":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","subjectId":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"},
});
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/audit_exports', {
  method: 'POST',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
  },
  body: JSON.stringify({
    "period": "2026-09",
    "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
    "subject_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
  }),
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_audit_exports_create(body={"period": "2026-09", "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "subject_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"})
import os
import uuid

import requests

response = requests.request(
    'POST',
    'https://sandbox.droomwork.io/v1/remittance/audit_exports',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
        'Idempotency-Key': str(uuid.uuid4()),
    },
    json={"period": "2026-09", "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "subject_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"},
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceAuditExportsCreate($idempotencyKey, json_decode('{"period":"2026-09","authority_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","subject_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"}', true));
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/audit_exports');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
    'Content-Type: application/json',
    'Idempotency-Key: ' . bin2hex(random_bytes(16)),
  ],
  CURLOPT_POSTFIELDS => '{"period":"2026-09","authority_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","subject_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"}',
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceAuditExportsCreate(idempotencyKey, body);
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/audit_exports"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .header("Content-Type", "application/json")
    .header("Idempotency-Key", UUID.randomUUID().toString())
    .method("POST", HttpRequest.BodyPublishers.ofString("""
        {
          "period": "2026-09",
          "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
          "subject_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
        }
        """))
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceAuditExportsCreate(idempotencyKey, body);
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/remittance/audit_exports");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
request.Content = new StringContent("""
    {
      "period": "2026-09",
      "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "subject_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
    }
    """, Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceAuditExportsCreate(ctx).IdempotencyKey(key).RemitAuditExportCreateRequest(body).Execute()
body := strings.NewReader(`{
  "period": "2026-09",
  "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "subject_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
}`)
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/remittance/audit_exports", body)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "audit_export",
  "livemode": false,
  "mocked": true,
  "status": "generating",
  "scope": {
    "period": "2026-09",
    "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
    "subject_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
  },
  "download_url": "https://files.sandbox.droomwork.com/example",
  "signature": "example",
  "verification_instructions_url": "https://files.sandbox.droomwork.com/example",
  "receipt_count": 1
}
GET/v1/remittance/audit_exports/{audit_export_id}#

Read back a pack you asked for

remittance.audit_exports.retrieve

An audit pack is one file holding the receipts for the month, authority or employee it was asked for. So the id that POST /v1/remittance/audit_exports returned brings the same pack back, without asking for it to be built again.

Send the pack's id in the path as audit_export_id. You get the pack's record again, with its status and, where there is one, the download_url to fetch the file from.

No call lists your packs, so the id is the only way back to one.

Path parameters

audit_export_id string required

The pack's identifier: the id of a pack you asked for at POST /v1/remittance/audit_exports. It starts with remit_authority_rail_return_; poll it here until status leaves generating.

Returns

The export.

id string required

The pack's identifier, first returned by POST /v1/remittance/audit_exports; it starts with remit_authority_rail_return_ and never changes. Pass it as audit_export_id to GET /v1/remittance/audit_exports/{audit_export_id} to poll the pack.

object always "audit_export" required

Always audit_export. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

status string required

generating while the pack is being built, ready once it can be downloaded and verified, failed when it could not be produced. Poll GET /v1/remittance/audit_exports/{audit_export_id} until it leaves generating.

generatingreadyfailed
scope object required

What the pack covers, as the one scope you named when you asked for it: a period, an authority_id or a subject_id. The other two are null.

3 fields
period string · nullable optional

The month the pack covers, as YYYY-MM, when you scoped it by period. null when you scoped it by authority or by employee.

authority_id string · nullable optional

The authority the pack covers, when you scoped it by authority: the authority_id you sent to POST /v1/remittance/audit_exports, an id from GET /v1/remittance/authorities. null when you scoped it by period or by employee.

subject_id string · nullable optional

The employee the pack covers, when you scoped it by employee: the subject_id you sent to POST /v1/remittance/audit_exports, their subject identifier starting with sub_. null when you scoped it by period or by authority.

download_url string · uri · nullable optional

Where to fetch the pack, as a URL, once status is ready; null before then and when the pack failed. Verify what you download against signature.

signature string · nullable optional

Verify the pack against this without trusting the system that made it.

verification_instructions_url string · uri · nullable optional

Where to read how to check the pack against its signature, as a URL; null until the pack is ready. Hand it on with the pack, so whoever receives it can verify it without trusting where it came from.

receipt_count integer optional

How many vaulted receipts the pack holds for the scope you named. Compare it with your own count before you send the pack on; 0 means nothing was vaulted in that scope.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X GET "https://sandbox.droomwork.io/v1/remittance/audit_exports/%7Baudit_export_id%7D" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceAuditExportsRetrieve({ auditExportId: '{audit_export_id}' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/audit_exports/%7Baudit_export_id%7D', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_audit_exports_retrieve(audit_export_id='{audit_export_id}')
import os

import requests

response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/audit_exports/%7Baudit_export_id%7D',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceAuditExportsRetrieve(audit_export_id: '{audit_export_id}');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/audit_exports/%7Baudit_export_id%7D');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceAuditExportsRetrieve("{audit_export_id}");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/audit_exports/%7Baudit_export_id%7D"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceAuditExportsRetrieve(auditExportId: "{audit_export_id}");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/audit_exports/%7Baudit_export_id%7D");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceAuditExportsRetrieve(ctx, "{audit_export_id}").Execute()
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/audit_exports/%7Baudit_export_id%7D", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "audit_export",
  "livemode": false,
  "mocked": true,
  "status": "generating",
  "scope": {
    "period": "2026-09",
    "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
    "subject_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
  },
  "download_url": "https://files.sandbox.droomwork.com/example",
  "signature": "example",
  "verification_instructions_url": "https://files.sandbox.droomwork.com/example",
  "receipt_count": 1
}
GET/v1/remittance/reconciliations#

Check your ring fenced account, day by day

remittance.reconciliations.list

This gives you the reconciliations your organisation holds, each one a day of the ring fenced account your statutory money moves through. So a screen in your product can carry a row for each day, and a reader sees which of them did not balance without opening one.

Every record carries the day as on, a balanced flag and any breaks recorded against that day, each break with the amount it is out by, in whole minor units with its currency.

Carry a record's id as reconciliation_id to read one day in full at GET /v1/remittance/reconciliations/{reconciliation_id}.

Query parameters

limit integer optional

How many records to return on one page, from 1 to 100, and 25 if you leave it out. When has_more is true, pass the last record's id as starting_after to get the next page.

on string optional

Return only the reconciliation for one day, as YYYY-MM-DD, such as 2026-09-01: the on each reconciliation carries. Leave it out to get every day.

Returns

A page of reconciliations, each with the balances either end of the day, where the record has them.

object always "list" required

Always list. Tells you which kind of record you are looking at, so one handler can read any response.

data array of Reconciliation required

The records on this page, in the order the list promises. Empty when nothing matched.

9 fields of Reconciliation
id string required

The reconciliation's identifier, as listed at GET /v1/remittance/reconciliations; it starts with remit_authority_rail_return_ and never changes. Pass it as reconciliation_id to GET /v1/remittance/reconciliations/{reconciliation_id}.

object always "reconciliation" required

Always reconciliation. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

on string · date required

The day this reconciliation is for, as YYYY-MM-DD, such as 2026-09-01. One is produced for every day; filter the list by it with the on query.

balanced boolean required

Every kobo debited is a kobo credited, with no commingling.

opening_balance Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

closing_balance Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

breaks array of object required

Empty when balanced is true.

3 fields
code string required

Which kind of break this is, as a code you can match on, such as no_payee_destination. detail says what it means in words.

detail string required

What went wrong, in words for a person to read, such as The payee has no verified destination, so this line cannot be paid. Match on code rather than on this text.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

has_more boolean required

true when there are more records after this page. Pass the last record's id as starting_after to get the next page.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
# query parameters: limit (optional), on (optional)
curl -X GET "https://sandbox.droomwork.io/v1/remittance/reconciliations?limit=25&on=2026-09-01" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

// query parameters: limit (optional), on (optional)
const result = await api.remittanceReconciliationsList({ limit: 25, on: '2026-09-01' });
// query parameters: limit (optional), on (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/reconciliations?limit=25&on=2026-09-01', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

# query parameters: limit (optional), on (optional)
result = api.remittance_reconciliations_list(limit=25, on='2026-09-01')
import os

import requests

# query parameters: limit (optional), on (optional)
response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/reconciliations?limit=25&on=2026-09-01',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

# query parameters: limit (optional), on (optional)
$result = $api->remittanceReconciliationsList(limit: 25, on: '2026-09-01');
<?php
// query parameters: limit (optional), on (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/reconciliations?limit=25&on=2026-09-01');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

// query parameters: limit (optional), on (optional)
var result = api.remittanceReconciliationsList(25, "2026-09-01");
// query parameters: limit (optional), on (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/reconciliations?limit=25&on=2026-09-01"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

// query parameters: limit (optional), on (optional)
var result = api.RemittanceReconciliationsList(limit: 25, on: "2026-09-01");
// query parameters: limit (optional), on (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/reconciliations?limit=25&on=2026-09-01");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

// query parameters: limit (optional), on (optional)
result, _, err := client.REMITAPI.RemittanceReconciliationsList(ctx).Limit(25).On("2026-09-01").Execute()
// query parameters: limit (optional), on (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/reconciliations?limit=25&on=2026-09-01", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "object": "list",
  "data": [
    {
      "id": "remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "object": "reconciliation",
      "livemode": false,
      "mocked": true,
      "on": "2026-09-01",
      "balanced": true,
      "breaks": [
        {
          "code": "no_payee_destination",
          "detail": "The payee has no verified destination, so this line cannot be paid.",
          "amount": {
            "amount": 7500000,
            "currency": "NGN"
          }
        }
      ],
      "opening_balance": {
        "amount": 0,
        "currency": "NGN"
      },
      "closing_balance": {
        "amount": 41250000,
        "currency": "NGN"
      }
    }
  ],
  "has_more": true
}
GET/v1/remittance/reconciliations/{reconciliation_id}#

See one day's debits against its credits

remittance.reconciliations.retrieve

A reconciliation is one day of the ring fenced account your statutory money moves through, and it says whether every kobo debited that day was a kobo credited, with nothing commingled. So one screen can show a break in words a person reads while your own code matches on the break's code.

Send the day's reconciliation_id in the path. You get the day as on, balanced, every break with the amount it is out by, in whole minor units with its currency, and the opening and closing balances where the record carries them.

Nothing else waits on this call. See the other days at GET /v1/remittance/reconciliations.

Path parameters

reconciliation_id string required

The reconciliation's identifier: the id of a reconciliation listed at GET /v1/remittance/reconciliations, starting with remit_authority_rail_return_. Each one is a day's proof that every kobo debited was a kobo credited.

Returns

The reconciliation, with no account number anywhere on it, only the day's own figures.

id string required

The reconciliation's identifier, as listed at GET /v1/remittance/reconciliations; it starts with remit_authority_rail_return_ and never changes. Pass it as reconciliation_id to GET /v1/remittance/reconciliations/{reconciliation_id}.

object always "reconciliation" required

Always reconciliation. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

on string · date required

The day this reconciliation is for, as YYYY-MM-DD, such as 2026-09-01. One is produced for every day; filter the list by it with the on query.

balanced boolean required

Every kobo debited is a kobo credited, with no commingling.

opening_balance Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

closing_balance Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

breaks array of object required

Empty when balanced is true.

3 fields
code string required

Which kind of break this is, as a code you can match on, such as no_payee_destination. detail says what it means in words.

detail string required

What went wrong, in words for a person to read, such as The payee has no verified destination, so this line cannot be paid. Match on code rather than on this text.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X GET "https://sandbox.droomwork.io/v1/remittance/reconciliations/%7Breconciliation_id%7D" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceReconciliationsRetrieve({ reconciliationId: '{reconciliation_id}' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/reconciliations/%7Breconciliation_id%7D', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_reconciliations_retrieve(reconciliation_id='{reconciliation_id}')
import os

import requests

response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/reconciliations/%7Breconciliation_id%7D',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceReconciliationsRetrieve(reconciliation_id: '{reconciliation_id}');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/reconciliations/%7Breconciliation_id%7D');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceReconciliationsRetrieve("{reconciliation_id}");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/reconciliations/%7Breconciliation_id%7D"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceReconciliationsRetrieve(reconciliationId: "{reconciliation_id}");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/reconciliations/%7Breconciliation_id%7D");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceReconciliationsRetrieve(ctx, "{reconciliation_id}").Execute()
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/reconciliations/%7Breconciliation_id%7D", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "reconciliation",
  "livemode": false,
  "mocked": true,
  "on": "2026-09-01",
  "balanced": true,
  "breaks": [
    {
      "code": "no_payee_destination",
      "detail": "The payee has no verified destination, so this line cannot be paid.",
      "amount": {
        "amount": 7500000,
        "currency": "NGN"
      }
    }
  ],
  "opening_balance": {
    "amount": 0,
    "currency": "NGN"
  },
  "closing_balance": {
    "amount": 41250000,
    "currency": "NGN"
  }
}
GET/v1/remittance/returns#

Where each filing to an authority has reached

remittance.returns.list

This gives you the employer returns your organisation holds, which are the filings you owe each authority, not the payments you made to them. So a screen can set what you owe each authority side by side, one row for each period you have a return for.

Each record carries its kind, the authority_id it is filed with, the period it covers and its status, with the id you need for everything that follows.

Carry a row's id as return_id to read it in full at GET /v1/remittance/returns/{return_id}, or to approve it at POST /v1/remittance/returns/{return_id}/approve.

Query parameters

limit integer optional

How many records to return on one page, from 1 to 100, and 25 if you leave it out. When has_more is true, pass the last record's id as starting_after to get the next page.

starting_after string optional

The id of the last record on the previous page of this same list. Leave it out to get the first page; when a page comes back with has_more true, send its last record's id here to get the page after it.

status string optional

Restricts the list to returns in one state: draft or pending_approval (not yet approved), approved, submitted (filed), accepted or rejected (the authority's answer). Leave it out to get every return.

draftpending_approvalapprovedsubmittedacceptedrejected

Returns

A page of returns.

object always "list" required

Always list. Tells you which kind of record you are looking at, so one handler can read any response.

data array of EmployerReturn required

The records on this page, in the order the list promises. Empty when nothing matched.

13 fields of EmployerReturn
id string required

The return's identifier, first given by POST /v1/remittance/returns and on every record of GET /v1/remittance/returns. It starts with remit_authority_rail_return_ and never changes; pass it as return_id to retrieve, approve or submit.

object always "employer_return" required

Always employer_return. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

kind string required
monthly_payeannual_payepension_schedulenhf_schedulensitf_returnitf_returnnhia_schedule
status string required
draftpending_approvalapprovedsubmittedacceptedrejected
authority_id string required

The authority this return is filed with: the id of an authority from GET /v1/remittance/authorities, which starts with remit_authority_rail_obligation_. It is the authority_id you sent when you generated the return.

period string required

The period the return covers, as you named it: YYYY-MM for a month, YYYY for a whole year. For example 2026-09.

generated_from array of string optional

The vaulted receipts this return was generated from.

totals object optional

What the return declares, summed from the vaulted receipts it was generated from: how many employees and the total amount.

2 fields
employee_count integer optional

How many employees the return declares for the period.

total Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

approved_by string · nullable optional

A named person. Required before submission.

submitted_at string · date-time · nullable optional

When the return was filed with the authority, as an RFC 3339 timestamp in UTC. null until you submit it.

authority_reference string · nullable optional

The reference the authority gave your filing, such as paye-2026-09-rivers. null until the authority has issued one.

has_more boolean required

true when there are more records after this page. Pass the last record's id as starting_after to get the next page.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
# query parameters: limit (optional), starting_after (optional), status (optional)
curl -X GET "https://sandbox.droomwork.io/v1/remittance/returns?limit=25&status=draft" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

// query parameters: limit (optional), starting_after (optional), status (optional)
const result = await api.remittanceReturnsList({ limit: 25, status: 'draft' });
// query parameters: limit (optional), starting_after (optional), status (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/returns?limit=25&status=draft', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

# query parameters: limit (optional), starting_after (optional), status (optional)
result = api.remittance_returns_list(limit=25, status='draft')
import os

import requests

# query parameters: limit (optional), starting_after (optional), status (optional)
response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/returns?limit=25&status=draft',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

# query parameters: limit (optional), starting_after (optional), status (optional)
$result = $api->remittanceReturnsList(limit: 25, status: 'draft');
<?php
// query parameters: limit (optional), starting_after (optional), status (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/returns?limit=25&status=draft');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;
import com.useheros.sdk.model.*;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

// query parameters: limit (optional), starting_after (optional), status (optional)
var result = api.remittanceReturnsList(25, null, RemitReturnStatus.fromValue("draft"));
// query parameters: limit (optional), starting_after (optional), status (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/returns?limit=25&status=draft"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

// query parameters: limit (optional), starting_after (optional), status (optional)
var result = api.RemittanceReturnsList(limit: 25, status: RemitReturnStatus.Draft);
// query parameters: limit (optional), starting_after (optional), status (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/returns?limit=25&status=draft");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

// query parameters: limit (optional), starting_after (optional), status (optional)
result, _, err := client.REMITAPI.RemittanceReturnsList(ctx).Limit(25).Status(heros.RemitReturnStatus("draft")).Execute()
// query parameters: limit (optional), starting_after (optional), status (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/returns?limit=25&status=draft", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "object": "list",
  "data": [
    {
      "id": "remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "object": "employer_return",
      "livemode": false,
      "mocked": true,
      "kind": "monthly_paye",
      "status": "draft",
      "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "period": "2026-09",
      "generated_from": [
        "example"
      ],
      "totals": {
        "employee_count": 1,
        "total": {
          "amount": 57900000,
          "currency": "NGN"
        }
      },
      "approved_by": "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "submitted_at": "2026-09-01T09:00:00Z",
      "authority_reference": "paye-2026-09-rivers"
    }
  ],
  "has_more": true
}
POST/v1/remittance/returns#

Produce a period's filing for one authority

remittance.returns.create

This opens the employer return for one period and one authority, which is the filing you owe them, not the payment you made to them. So your own system never has to total a period: the figures are taken from the receipts already in your vault.

Send the filing's kind, the authority_id to file with and the period it covers. You get the return back in draft, with the id you will approve and submit it by.

The receipts for that period and authority must already be in your vault, where executing a remittance at POST /v1/remittance/remittances/{remittance_id}/execute puts them.

Match period to the kind you asked for: YYYY-MM for a month, YYYY for a whole year.

Approve it at POST /v1/remittance/returns/{return_id}/approve before anything can be filed, passing the id as return_id.

Headers

Idempotency-Key string required

A key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.

Body

kind string required
monthly_payeannual_payepension_schedulenhf_schedulensitf_returnitf_returnnhia_schedule
authority_id string required

The authority to file with: the id of an authority from GET /v1/remittance/authorities, which starts with remit_authority_rail_obligation_. The return is generated from your vaulted receipts for that authority.

period string required

The period to file for, as YYYY-MM for a month or YYYY for a whole year, such as 2026-09. The figures come from your vaulted receipts for that period, not from you.

Returns

The new filing, with the totals it declares, so what will be filed can be checked first.

id string required

The return's identifier, first given by POST /v1/remittance/returns and on every record of GET /v1/remittance/returns. It starts with remit_authority_rail_return_ and never changes; pass it as return_id to retrieve, approve or submit.

object always "employer_return" required

Always employer_return. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

kind string required
monthly_payeannual_payepension_schedulenhf_schedulensitf_returnitf_returnnhia_schedule
status string required
draftpending_approvalapprovedsubmittedacceptedrejected
authority_id string required

The authority this return is filed with: the id of an authority from GET /v1/remittance/authorities, which starts with remit_authority_rail_obligation_. It is the authority_id you sent when you generated the return.

period string required

The period the return covers, as you named it: YYYY-MM for a month, YYYY for a whole year. For example 2026-09.

generated_from array of string optional

The vaulted receipts this return was generated from.

totals object optional

What the return declares, summed from the vaulted receipts it was generated from: how many employees and the total amount.

2 fields
employee_count integer optional

How many employees the return declares for the period.

total Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

approved_by string · nullable optional

A named person. Required before submission.

submitted_at string · date-time · nullable optional

When the return was filed with the authority, as an RFC 3339 timestamp in UTC. null until you submit it.

authority_reference string · nullable optional

The reference the authority gave your filing, such as paye-2026-09-rivers. null until the authority has issued one.

Other responses

400The request could not be read, or a value was refused.
401No valid credential was presented.
403The credential does not carry the required scope.
422A required fact is missing. Call the readiness endpoint to see what.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X POST "https://sandbox.droomwork.io/v1/remittance/returns" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"kind":"monthly_paye","authority_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","period":"2026-09"}'
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceReturnsCreate({
  idempotencyKey: crypto.randomUUID(),
  remitEmployerReturnCreateRequest: {"kind":"monthly_paye","authorityId":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","period":"2026-09"},
});
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/returns', {
  method: 'POST',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
  },
  body: JSON.stringify({
    "kind": "monthly_paye",
    "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
    "period": "2026-09"
  }),
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_returns_create(body={"kind": "monthly_paye", "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "period": "2026-09"})
import os
import uuid

import requests

response = requests.request(
    'POST',
    'https://sandbox.droomwork.io/v1/remittance/returns',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
        'Idempotency-Key': str(uuid.uuid4()),
    },
    json={"kind": "monthly_paye", "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "period": "2026-09"},
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceReturnsCreate($idempotencyKey, json_decode('{"kind":"monthly_paye","authority_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","period":"2026-09"}', true));
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/returns');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
    'Content-Type: application/json',
    'Idempotency-Key: ' . bin2hex(random_bytes(16)),
  ],
  CURLOPT_POSTFIELDS => '{"kind":"monthly_paye","authority_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","period":"2026-09"}',
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceReturnsCreate(idempotencyKey, body);
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/returns"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .header("Content-Type", "application/json")
    .header("Idempotency-Key", UUID.randomUUID().toString())
    .method("POST", HttpRequest.BodyPublishers.ofString("""
        {
          "kind": "monthly_paye",
          "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
          "period": "2026-09"
        }
        """))
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceReturnsCreate(idempotencyKey, body);
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/remittance/returns");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
request.Content = new StringContent("""
    {
      "kind": "monthly_paye",
      "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "period": "2026-09"
    }
    """, Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceReturnsCreate(ctx).IdempotencyKey(key).RemitEmployerReturnCreateRequest(body).Execute()
body := strings.NewReader(`{
  "kind": "monthly_paye",
  "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "period": "2026-09"
}`)
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/remittance/returns", body)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "employer_return",
  "livemode": false,
  "mocked": true,
  "kind": "monthly_paye",
  "status": "draft",
  "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "period": "2026-09",
  "generated_from": [
    "example"
  ],
  "totals": {
    "employee_count": 1,
    "total": {
      "amount": 57900000,
      "currency": "NGN"
    }
  },
  "approved_by": "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "submitted_at": "2026-09-01T09:00:00Z",
  "authority_reference": "paye-2026-09-rivers"
}
GET/v1/remittance/returns/{return_id}#

One filing, and whether it is approved

remittance.returns.retrieve

An employer return is what you file with one authority for one period: the filing you owe them, not the payment you made to them. So a screen in your product can refresh a filing it saved earlier and see whether somebody has approved it yet.

Send the return_id in the path. You get the filing back: its kind, the authority_id it is for, the period it covers, and status for where it has got to.

Read status before you act on a filing you stored earlier: POST /v1/remittance/returns/{return_id}/approve is refused with conflict once it is approved, and POST /v1/remittance/returns/{return_id}/submit until it is.

Path parameters

return_id string required

The return's identifier: the id on the return POST /v1/remittance/returns gave you, or on any record of GET /v1/remittance/returns. It starts with remit_authority_rail_return_.

Returns

The filing, and the authority_reference the authority knows it by, so you can quote it when you ask them.

id string required

The return's identifier, first given by POST /v1/remittance/returns and on every record of GET /v1/remittance/returns. It starts with remit_authority_rail_return_ and never changes; pass it as return_id to retrieve, approve or submit.

object always "employer_return" required

Always employer_return. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

kind string required
monthly_payeannual_payepension_schedulenhf_schedulensitf_returnitf_returnnhia_schedule
status string required
draftpending_approvalapprovedsubmittedacceptedrejected
authority_id string required

The authority this return is filed with: the id of an authority from GET /v1/remittance/authorities, which starts with remit_authority_rail_obligation_. It is the authority_id you sent when you generated the return.

period string required

The period the return covers, as you named it: YYYY-MM for a month, YYYY for a whole year. For example 2026-09.

generated_from array of string optional

The vaulted receipts this return was generated from.

totals object optional

What the return declares, summed from the vaulted receipts it was generated from: how many employees and the total amount.

2 fields
employee_count integer optional

How many employees the return declares for the period.

total Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

approved_by string · nullable optional

A named person. Required before submission.

submitted_at string · date-time · nullable optional

When the return was filed with the authority, as an RFC 3339 timestamp in UTC. null until you submit it.

authority_reference string · nullable optional

The reference the authority gave your filing, such as paye-2026-09-rivers. null until the authority has issued one.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X GET "https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceReturnsRetrieve({ returnId: 'remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_returns_retrieve(return_id='remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')
import os

import requests

response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceReturnsRetrieve(return_id: 'remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceReturnsRetrieve("remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceReturnsRetrieve(returnId: "remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceReturnsRetrieve(ctx, "remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "employer_return",
  "livemode": false,
  "mocked": true,
  "kind": "monthly_paye",
  "status": "draft",
  "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "period": "2026-09",
  "generated_from": [
    "example"
  ],
  "totals": {
    "employee_count": 1,
    "total": {
      "amount": 57900000,
      "currency": "NGN"
    }
  },
  "approved_by": "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "submitted_at": "2026-09-01T09:00:00Z",
  "authority_reference": "paye-2026-09-rivers"
}
POST/v1/remittance/returns/{return_id}/approve#

Approve a return for submission

remittance.returns.approve

This records the decision that a filing should go to the authority as it stands. So the moment a person signs a filing off becomes an event your product can act on, and approving files nothing by itself.

Send the return_id in the path and no request body. You get the filing back with status moved to approved, which is the only state submission runs from.

The filing has to exist, from POST /v1/remittance/returns, and be in draft or pending_approval.

A return already approved or submitted is refused with conflict. The event it publishes is return.approved. File it at POST /v1/remittance/returns/{return_id}/submit when you want it filed.

Path parameters

return_id string required

The return's identifier: the id on the return POST /v1/remittance/returns gave you, or on any record of GET /v1/remittance/returns. It starts with remit_authority_rail_return_.

Headers

Idempotency-Key string required

A key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.

Returns

The filing with a named person on it, so one name answers for it from here on.

id string required

The return's identifier, first given by POST /v1/remittance/returns and on every record of GET /v1/remittance/returns. It starts with remit_authority_rail_return_ and never changes; pass it as return_id to retrieve, approve or submit.

object always "employer_return" required

Always employer_return. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

kind string required
monthly_payeannual_payepension_schedulenhf_schedulensitf_returnitf_returnnhia_schedule
status string required
draftpending_approvalapprovedsubmittedacceptedrejected
authority_id string required

The authority this return is filed with: the id of an authority from GET /v1/remittance/authorities, which starts with remit_authority_rail_obligation_. It is the authority_id you sent when you generated the return.

period string required

The period the return covers, as you named it: YYYY-MM for a month, YYYY for a whole year. For example 2026-09.

generated_from array of string optional

The vaulted receipts this return was generated from.

totals object optional

What the return declares, summed from the vaulted receipts it was generated from: how many employees and the total amount.

2 fields
employee_count integer optional

How many employees the return declares for the period.

total Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

approved_by string · nullable optional

A named person. Required before submission.

submitted_at string · date-time · nullable optional

When the return was filed with the authority, as an RFC 3339 timestamp in UTC. null until you submit it.

authority_reference string · nullable optional

The reference the authority gave your filing, such as paye-2026-09-rivers. null until the authority has issued one.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.
409The record is not in a state that allows this.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X POST "https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/approve" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceReturnsApprove({ returnId: 'remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/approve', {
  method: 'POST',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
    'Idempotency-Key': crypto.randomUUID(),
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_returns_approve(return_id='remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')
import os
import uuid

import requests

response = requests.request(
    'POST',
    'https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/approve',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
        'Idempotency-Key': str(uuid.uuid4()),
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceReturnsApprove(return_id: 'remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/approve');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
    'Idempotency-Key: ' . bin2hex(random_bytes(16)),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceReturnsApprove("remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/approve"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .header("Idempotency-Key", UUID.randomUUID().toString())
    .method("POST", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceReturnsApprove(returnId: "remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/approve");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceReturnsApprove(ctx, "remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/approve", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "employer_return",
  "livemode": false,
  "mocked": true,
  "kind": "monthly_paye",
  "status": "approved",
  "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "period": "2026-09",
  "generated_from": [
    "example"
  ],
  "totals": {
    "employee_count": 1,
    "total": {
      "amount": 57900000,
      "currency": "NGN"
    }
  },
  "approved_by": "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "submitted_at": "2026-09-01T09:00:00Z",
  "authority_reference": "paye-2026-09-rivers"
}
POST/v1/remittance/returns/{return_id}/submit#

Submit an approved return to the authority

remittance.returns.submit

This files the return with the authority, which is the last step of the filing you drew up. So nothing reaches an authority before it has been approved, and a filing leaves only on the call you make to send it.

Send the return_id in the path and no request body. You get the whole filing back with status moved to submitted: its kind, authority_id and period are as you left them.

The filing has to be approved first, which POST /v1/remittance/returns/{return_id}/approve does.

A return that has not been approved is refused with conflict, and so is one already submitted. Nothing else waits on this call.

Path parameters

return_id string required

The return's identifier: the id on the return POST /v1/remittance/returns gave you, or on any record of GET /v1/remittance/returns. It starts with remit_authority_rail_return_.

Headers

Idempotency-Key string required

A key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.

Returns

Submission accepted.

id string required

The return's identifier, first given by POST /v1/remittance/returns and on every record of GET /v1/remittance/returns. It starts with remit_authority_rail_return_ and never changes; pass it as return_id to retrieve, approve or submit.

object always "employer_return" required

Always employer_return. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

kind string required
monthly_payeannual_payepension_schedulenhf_schedulensitf_returnitf_returnnhia_schedule
status string required
draftpending_approvalapprovedsubmittedacceptedrejected
authority_id string required

The authority this return is filed with: the id of an authority from GET /v1/remittance/authorities, which starts with remit_authority_rail_obligation_. It is the authority_id you sent when you generated the return.

period string required

The period the return covers, as you named it: YYYY-MM for a month, YYYY for a whole year. For example 2026-09.

generated_from array of string optional

The vaulted receipts this return was generated from.

totals object optional

What the return declares, summed from the vaulted receipts it was generated from: how many employees and the total amount.

2 fields
employee_count integer optional

How many employees the return declares for the period.

total Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

approved_by string · nullable optional

A named person. Required before submission.

submitted_at string · date-time · nullable optional

When the return was filed with the authority, as an RFC 3339 timestamp in UTC. null until you submit it.

authority_reference string · nullable optional

The reference the authority gave your filing, such as paye-2026-09-rivers. null until the authority has issued one.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.
409The record is not in a state that allows this.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X POST "https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/submit" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceReturnsSubmit({ returnId: 'remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/submit', {
  method: 'POST',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
    'Idempotency-Key': crypto.randomUUID(),
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_returns_submit(return_id='remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')
import os
import uuid

import requests

response = requests.request(
    'POST',
    'https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/submit',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
        'Idempotency-Key': str(uuid.uuid4()),
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceReturnsSubmit(return_id: 'remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/submit');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
    'Idempotency-Key: ' . bin2hex(random_bytes(16)),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceReturnsSubmit("remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/submit"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .header("Idempotency-Key", UUID.randomUUID().toString())
    .method("POST", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceReturnsSubmit(returnId: "remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/submit");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceReturnsSubmit(ctx, "remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/remittance/returns/remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/submit", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "employer_return",
  "livemode": false,
  "mocked": true,
  "kind": "monthly_paye",
  "status": "submitted",
  "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "period": "2026-09",
  "generated_from": [
    "example"
  ],
  "totals": {
    "employee_count": 1,
    "total": {
      "amount": 57900000,
      "currency": "NGN"
    }
  },
  "approved_by": "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "submitted_at": "2026-09-01T09:00:00Z",
  "authority_reference": "paye-2026-09-rivers"
}
GET/v1/remittance/readiness#

What REMIT needs before it files anything

remittance.readiness.retrieve

A filing rests on facts REMIT has to have before anything reaches an authority, and this is where they are written down. The list tells you which facts you may attest to and which are gates no attestation lifts, so the shape of the integration is settled before you build any of it.

Send no parameters. You get rows, one per fact REMIT asks for, naming the fact, its owner and the assurance it has to reach, and always_enforced beside them.

Nothing else waits on this call.

Returns

The readiness report.

object always "readiness_report" required

Always readiness_report. Tells you which kind of record you are looking at, so one handler can read any response.

module string required

The module whose readiness endpoint you called, such as GET /v1/payroll/readiness: anchor (identity), proof (credentials), rail (engagements), flow (sourcing), match (allocation), run (payroll), remit (remittance) or route (payouts).

anchorproofrailflowmatchrunremitroute
mode string required

integrated means a required fact comes from the Heros module that owns it; standalone means you supply it yourself under an attestation. The checks are the same in both, and what each fact is worth is recorded on its row as held.

integratedstandalone
ready boolean required

true when every row is satisfied and the module has what it needs from you. false when a required fact is missing or held at too low an assurance; rows says which.

rows array of ReadinessRow required

One row per fact the module requires: who owns it, the assurance it needs, what you hold and whether that satisfies it. The rows that are not satisfied are what to bring.

8 fields of ReadinessRow
fact string required

Named for what it is, not for who supplies it.

owner string required

The sibling module that owns this fact when running integrated.

contract_row string optional
required string required

How a fact was established. Recorded on the fact rather than in configuration, so an attested identity and a verified one stay distinguishable a year later, which is the distinction that matters when something is disputed.

attestedverified
held one of required
Assuranceor
source string · nullable optional
integratedstandalonenull
satisfied boolean required
missing_because string · nullable optional
not_suppliedassurance_too_lownull
always_enforced array of string optional

Gates that hold in every mode and cannot be attested away. Consent before any source is queried, bank account validation, the tax identifiers returns are filed under, and duplicate detection within the organisation's own population.

authorities_without_credentials array of string optional

Filing cannot proceed for these until credentials are supplied.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X GET "https://sandbox.droomwork.io/v1/remittance/readiness" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceReadinessRetrieve({});
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/readiness', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_readiness_retrieve()
import os

import requests

response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/readiness',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceReadinessRetrieve();
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/readiness');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceReadinessRetrieve();
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/readiness"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceReadinessRetrieve();
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/readiness");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceReadinessRetrieve(ctx).Execute()
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/readiness", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "object": "readiness_report",
  "module": "remit",
  "mode": "integrated",
  "ready": true,
  "rows": [
    {
      "fact": "instruction_set",
      "owner": "run",
      "contract_row": "6.2.1",
      "required": "attested",
      "held": "attested",
      "source": "integrated",
      "satisfied": true,
      "missing_because": null
    }
  ],
  "always_enforced": [
    "consent_token",
    "bank_account_validation",
    "tax_identifier_validation",
    "duplicate_detection"
  ],
  "authorities_without_credentials": []
}
POST/v1/remittance/instruction_sets/{instruction_set_id}/reject#

Reject figures you do not want filed

remittance.instruction_sets.reject

This closes a submission you will not file. A rejected set is final: nothing is remitted against it and nothing moves it back, so a month you decided against cannot be committed later by another call or another system.

Send no request body. You get the whole set back, with its status now rejected and the figures it held kept as a record of what was sent.

The set must be waiting on your decision, which is where POST /v1/remittance/instruction_sets leaves it.

A month you rejected is submitted again as a new set at POST /v1/remittance/instruction_sets, and a rejected set is never corrected in place. A set that is no longer waiting on your decision is refused with conflict.

Path parameters

instruction_set_id string required

The set's identifier: the id returned by POST /v1/remittance/instruction_sets or listed at GET /v1/remittance/instruction_sets, or an import's instruction_set_id. It starts with remit_authority_rail_instruction_.

Headers

Idempotency-Key string required

A key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.

Returns

The set, with no field on it recording who decided against it.

id string required

The set's identifier, starting remit_authority_rail_instruction_, as listed at GET /v1/remittance/instruction_sets. It never changes; pass it as instruction_set_id to retrieve, accept, reject or remit the set.

object always "ingested_instruction_set" required

Always ingested_instruction_set. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

status string required

Nothing is committed until accepted.

receivedvalidatingpending_acceptanceacceptedrejected
source string required

Where the set came from. Heros payroll or your own, by API or by file. Everything downstream behaves identically whichever it was.

runexternal_apiexternal_file
period string required

The month the set covers, as YYYY-MM, such as 2026-09. Filter the list by it with the period query.

run_id string · nullable optional

The Heros payroll run the set came from, by its id from POST /v1/payroll/runs or GET /v1/payroll/runs, starting run_enterprise_. Present when source is run; null when the set came from your own payroll.

instructions InstructionSet optional

What is owed to whom for one run. This shape is owned jointly by RUN and REMIT. RUN row 19 emits it and REMIT row 1 ingests it, from RUN and from external payroll alike. It lives here rather than in either module document so the two cannot drift, which is the failure that would otherwise surface at M3 with RUN already accepted and paid. Totals reconcile to run totals to the kobo, because they sum payslip lines rather than recompute from an aggregate. This is the object REMIT ingests.

11 fields of InstructionSet
id string required

The instruction set's identifier, which never changes: read it at GET /v1/payroll/runs/{run_id}/instruction_set when Heros ran the payroll, and send the set on unchanged to POST /v1/remittance/instruction_sets. Quote it when you ask about the set.

object always "instruction_set" required

Always instruction_set. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

run_id string required

The payroll run this set is owed for, by its id from POST /v1/payroll/runs, which starts with run_enterprise_. The set's totals reconcile to that run's totals to the kobo.

period string optional

The pay period the amounts are owed for, as year and month, for example 2026-09.

paye array of object required

Grouped by the State IRS of the employee's residence, not the employer's location.

5 fields
authority_id string required

The State Internal Revenue Service this PAYE is owed to, by its id from GET /v1/remittance/authorities, which starts with remit_authority_rail_obligation_. Use it wherever a call names the authority.

jurisdiction string required

The State Internal Revenue Service this line is grouped under, named in full, for example Rivers State Internal Revenue Service. Read it to label the line; authority_id names the authority in a call.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

payee_count integer optional

How many employees this line's PAYE covers. Optional; when it is present, check it against your own headcount for that state.

reconciliation_reference string required

The reference that identifies this line when you reconcile it, for example paye-2026-09-rivers. Keep it with your own records so you can trace the line later.

pension array of object required

Grouped by administrator and retirement savings account number.

6 fields
administrator_id string required

The Pension Fund Administrator these contributions are owed to, by its id from GET /v1/remittance/authorities with kind=pension_administrator, which starts with remit_authority_rail_obligation_. Use it wherever a call names the administrator.

administrator_name string optional

The administrator's name in full, so you can label the line without a second call. Optional; administrator_id is what names the administrator in a call.

employee_amount Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

employer_amount Money optional
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

reconciliation_reference string required

The reference that identifies this line when you reconcile it. Keep it with your own records so you can trace the line later.

levies array of object required

NHF, NSITF, ITF and NHIA totals, each with a reconciliation reference.

3 fields
code string required

Which levy this line is for: nhf the National Housing Fund, nsitf the Nigeria Social Insurance Trust Fund, itf the Industrial Training Fund, nhia the National Health Insurance Authority. One line per levy.

nhfnsitfitfnhia
amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

reconciliation_reference string required

The reference that identifies this levy line when you reconcile it. Keep it with your own records so you can trace the line later.

totals object required

The set's grand total, which its lines sum to. From a Heros run it reconciles to the run's totals to the kobo.

1 field
total Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

created_at string · date-time optional

When the record was created, as an RFC 3339 timestamp in UTC.

validation_report ValidationReport required

The result of checking a submission before anything is committed. Names every failing entry rather than stopping at the first, so one submission tells you everything to fix. The same shape wherever the platform ingests, validates and reports, which is every bulk intake in every module.

4 fields of ValidationReport
entry_count integer · minimum 0 required

How many entries the submission held: every row in the file or line in the instruction set, whether it passed or not.

error_count integer · minimum 0 required

How many entries failed with an error. Each is named in entries with its position and why, so one submission tells you everything to fix.

warning_count integer · minimum 0 required

How many entries passed with a warning, each named in entries. A warning does not fail the entry; it points at something to confirm before you go ahead.

entries array of object optional

One item per error or warning found, with the row or line it sits on, its severity, a code and what was wrong. Empty or absent when every entry passed clean.

4 fields
index integer · minimum 1 required

The row in a file, or the line in an instruction set.

severity string required

error means the entry failed and must be fixed. warning means it passed, but points at something you should confirm before you go ahead.

errorwarning
code string required

Why the entry was flagged, as a code you can branch on. detail says the same in words and may change; the code does not.

detail string required

What was wrong with the entry, in plain words. Show it beside the row; it may change, so branch on code.

jurisdiction_pack object optional

The jurisdiction pack the set is pinned to, by identifier and version. Every line was recomputed against it, so its rules are the ones the validation report reflects.

2 fields
pack_id string optional

Which jurisdiction pack the set is pinned to, such as ng-paye. We publish the packs and you never send this; with version, it names exactly which rules every line was checked against, and it stays with the set so you can show which rules applied.

version string optional

The pack version the set was checked against, such as 2026.08.1. It's pinned, so a later pack release doesn't change what this set was judged by.

accepted_by string · nullable optional

Who accepted the set: the actor that called accept. null until the set is accepted.

created_at string · date-time optional

When the record was created, as an RFC 3339 timestamp in UTC.

Other responses

400The request could not be read, or a value was refused.
401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.
409The record is not in a state that allows this.
422A required fact is missing. Call the readiness endpoint to see what.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X POST "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/reject" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceInstructionSetsReject({ instructionSetId: 'remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/reject', {
  method: 'POST',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
    'Idempotency-Key': crypto.randomUUID(),
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_instruction_sets_reject(instruction_set_id='remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')
import os
import uuid

import requests

response = requests.request(
    'POST',
    'https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/reject',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
        'Idempotency-Key': str(uuid.uuid4()),
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceInstructionSetsReject(instruction_set_id: 'remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/reject');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
    'Idempotency-Key: ' . bin2hex(random_bytes(16)),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceInstructionSetsReject("remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/reject"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .header("Idempotency-Key", UUID.randomUUID().toString())
    .method("POST", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceInstructionSetsReject(instructionSetId: "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/reject");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceInstructionSetsReject(ctx, "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/remittance/instruction_sets/remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/reject", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "ingested_instruction_set",
  "livemode": false,
  "mocked": true,
  "status": "rejected",
  "source": "run",
  "period": "2026-09",
  "validation_report": {
    "entry_count": 0,
    "error_count": 0,
    "warning_count": 0,
    "entries": [
      {
        "index": 1,
        "severity": "error",
        "code": "invalid_money_amount",
        "detail": "The payee has no verified destination, so this line cannot be paid."
      }
    ]
  },
  "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "instructions": {
    "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
    "object": "instruction_set",
    "livemode": false,
    "mocked": true,
    "run_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
    "paye": [
      {
        "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
        "jurisdiction": "Rivers State Internal Revenue Service",
        "amount": {
          "amount": 7500000,
          "currency": "NGN"
        },
        "reconciliation_reference": "paye-2026-09-rivers",
        "payee_count": 1
      }
    ],
    "pension": [
      {
        "administrator_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
        "amount": {
          "amount": 7500000,
          "currency": "NGN"
        },
        "reconciliation_reference": "paye-2026-09-rivers",
        "administrator_name": "example",
        "employee_amount": {
          "amount": 4200000,
          "currency": "NGN"
        },
        "employer_amount": {
          "amount": 5400000,
          "currency": "NGN"
        }
      }
    ],
    "levies": [
      {
        "code": "nhf",
        "amount": {
          "amount": 7500000,
          "currency": "NGN"
        },
        "reconciliation_reference": "paye-2026-09-rivers"
      }
    ],
    "totals": {
      "total": {
        "amount": 57900000,
        "currency": "NGN"
      }
    },
    "period": "2026-09",
    "created_at": "2026-09-01T09:00:00Z"
  },
  "jurisdiction_pack": {
    "pack_id": "ng-paye",
    "version": "2026.08.1"
  },
  "accepted_by": "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "created_at": "2026-09-01T09:00:00Z"
}
POST/v1/remittance/remittances/{remittance_id}/execute#

Execute an approved remittance

remittance.remittances.execute

This is the call that files. Each leg of an approved remittance goes to its own authority, and what that authority acknowledges receiving comes back as a receipt in the vault, so your product can show a month's figures beside each authority's own proof of payment.

Send the remittance's id in the path and no request body. You get the whole remittance back, its total in whole minor units with its currency, and every leg with its own status and the amount it pays.

The remittance has to be approved first, at POST /v1/remittance/remittances/{remittance_id}/approve.

The proof of each filing is in the vault at GET /v1/remittance/receipts. A leg that came back failed is retried at POST /v1/remittance/remittances/{remittance_id}/legs/{leg_id}/retry. A remittance that is not approved is refused with conflict.

Path parameters

remittance_id string required

The remittance's identifier: the id of a remittance you created at POST /v1/remittance/remittances or listed at GET /v1/remittance/remittances. It starts with remit_authority_rail_remittance_.

Headers

Idempotency-Key string required

A key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.

Returns

The remittance, with created_at where there is one, which dates the record and not this call.

id string required

The remittance's identifier, first returned by POST /v1/remittance/remittances; it starts with remit_authority_rail_remittance_ and never changes. Pass it as remittance_id wherever a call names this remittance.

object always "remittance" required

Always remittance. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm this record is in: false is the sandbox, true is live. Read it before you act on anything.

mocked boolean required

Where these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.

status string required
draftapprovedexecutingcompletedpartially_completedfailed
instruction_set_id string required

The id of the accepted instruction set whose figures the legs pay, from POST /v1/remittance/instruction_sets, starting with remit_authority_rail_instruction_. Retrieve it at GET /v1/remittance/instruction_sets/{instruction_set_id}.

period string optional

The month the remittance pays for, as YYYY-MM, such as 2026-09. It's the period of the instruction set it was created from.

total Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

legs array of Leg required

One leg per authority the remittance pays, each with its own state, amount and receipt. A leg runs on its own, so one authority being down never holds the others; read each to see what settled where.

11 fields of Leg
id string required

The leg's identifier, first returned in legs on the remittance from POST /v1/remittance/remittances; it never changes. Pass it as leg_id, with the remittance's id as remittance_id, to retrieve or retry the leg.

object always "remittance_leg" required

Always remittance_leg. Tells you which kind of record you are looking at, so one handler can read any response.

remittance_id string optional

The id of the remittance this leg belongs to, from POST /v1/remittance/remittances; it starts with remit_authority_rail_remittance_. Every call that names the leg names it too, at /v1/remittance/remittances/{remittance_id}/legs/{leg_id}.

authority_id string required

The id of the authority this leg pays, as listed at GET /v1/remittance/authorities; it starts with remit_authority_rail_obligation_. Look it up at GET /v1/remittance/authorities/{authority_id} for its name, tier and capabilities.

authority_name string optional

The authority's name as you'd write it, such as Rivers State Internal Revenue Service. For display; authority_id is what you match on.

tier string optional

How the filing reaches the authority. Readable so you know what to expect on timing. Never something to code against, since all three present the same contract.

direct_apiportal_automationassisted_manual
status string required

A leg reaches completed only once its receipt is vaulted. quarantined means a receipt arrived but disagreed with the leg.

pendingexecutingawaiting_receiptcompletedquarantinedfailed
amount Money required
2 fields of Money
amount integer · int64 required

A whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.

currency string required

ISO 4217 code.

receipt_id string · nullable optional

The id of the receipt that is this leg's proof of payment, once vaulted; it starts with remit_authority_rail_receipt_ and you retrieve it at GET /v1/remittance/receipts/{receipt_id}. null until a receipt is vaulted.

attempts integer · minimum 0 optional

How many times filing this leg with its authority has been tried, retries included. 0 before the first try; read it with last_fault before you retry.

last_fault string · nullable optional

Why the latest attempt failed, in words for a person to read, such as The register did not answer within the timeout. null when there is no fault to report; read it before you retry.

approved_by string · nullable optional

Who approved the remittance: the actor that called approve. null while it is still draft, and execution is refused until a person is named here.

created_at string · date-time optional

When the record was created, as an RFC 3339 timestamp in UTC.

Other responses

400The request could not be read, or a value was refused.
401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.
409The record is not in a state that allows this.
422A required fact is missing. Call the readiness endpoint to see what.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X POST "https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/execute" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceRemittancesExecute({ remittanceId: 'remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/execute', {
  method: 'POST',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
    'Idempotency-Key': crypto.randomUUID(),
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_remittances_execute(remittance_id='remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')
import os
import uuid

import requests

response = requests.request(
    'POST',
    'https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/execute',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
        'Idempotency-Key': str(uuid.uuid4()),
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceRemittancesExecute(remittance_id: 'remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/execute');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
    'Idempotency-Key: ' . bin2hex(random_bytes(16)),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceRemittancesExecute("remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/execute"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .header("Idempotency-Key", UUID.randomUUID().toString())
    .method("POST", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceRemittancesExecute(remittanceId: "remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/execute");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceRemittancesExecute(ctx, "remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/remittance/remittances/remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/execute", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "remit_authority_rail_remittance_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "remittance",
  "livemode": false,
  "mocked": true,
  "status": "completed",
  "instruction_set_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "legs": [
    {
      "id": "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "object": "remittance_leg",
      "authority_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "status": "pending",
      "amount": {
        "amount": 7500000,
        "currency": "NGN"
      },
      "remittance_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "authority_name": "Sandbox State Internal Revenue Service",
      "tier": "direct_api",
      "receipt_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "attempts": 0,
      "last_fault": "The register did not answer within the timeout."
    }
  ],
  "total": {
    "amount": 57900000,
    "currency": "NGN"
  },
  "period": "2026-09",
  "approved_by": "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "created_at": "2026-09-01T09:00:00Z"
}
GET/v1/remittance/events#

Catch up on your remittance history

remittance.events.list

REMIT records what happens to the records it holds, and this reads those events back. Every event carries the record as it stood at that moment, so your product can show what changed on an instruction set or a return, not only where it stands now.

Send nothing and you get a page of events across your records, oldest first, each under an evt_ identifier. Pass a record's id as stream for that record's own history in sequence order.

after counts inside one stream, so it needs stream beside it. Across records you get the order REMIT recorded events in, which is not always occurred_at order.

An event says what happened to a record and never who did it. GET /v1/remittance/audit_entries is who, matched on request_id.

Open one at GET /v1/remittance/events/{event_id}. Until something has happened in REMIT, this comes back empty and not refused.

Query parameters

stream string optional

The id of the record whose events you want, such as an instruction set's (remit_authority_rail_instruction_…, from POST /v1/remittance/instruction_sets) or a return's (remit_authority_rail_return_…). Omit it to get every record's events.

after integer optional

The last sequence you handled on that record; you get the events after it, so 0 reads from the start. Send stream beside it, because a sequence counts within one record's events.

limit integer optional

How many records to return on one page, from 1 to 100, and 25 if you leave it out. When has_more is true, pass the last record's id as starting_after to get the next page.

starting_after string optional

The id of the last record on the previous page of this same list. Leave it out to get the first page; when a page comes back with has_more true, send its last record's id here to get the page after it.

Returns

A page of events, each with occurred_at, so your own log carries when each one happened.

object always "list" required

Always list. Tells you which kind of record you are looking at, so one handler can read any response.

data array of StoredEvent required

The records on this page, in the order the list promises. Empty when nothing matched.

13 fields of StoredEvent
id string required

The event's identifier, starting with evt_, the same on a webhook delivery and on the module's events list, such as GET /v1/payroll/events. It never changes: a redelivery carries the same id, so you can recognise an event you have already handled.

type string required

What happened, as module.resource.past_tense_verb, for example run.payslip.calculated. Pick your handler on it; data takes the shape this type promises.

schema_version integer · minimum 1 required

The version of the shape data takes for this type, starting at 1. A change to the shape raises it, so check it before you read data.

org_id string required

The organisation the event belongs to, by its id, which starts with org_: the one POST /v1/registrations gave you and GET /v1/me returns. You only ever receive events for your own organisation.

sequence integer · minimum 0 required

Per organisation and per stream. It is how a consumer tells a replay from a new event, and it is what the delivery guarantee rests on.

occurred_at string · date-time required

When the event happened, as an RFC 3339 timestamp in UTC. Not when it was delivered: a redelivery carries the original value.

request_id string optional

The request that caused this event, where one did: the Droomwork-Request-Id that request returned, starting with req_. Absent for an event a schedule raised, such as an engagement lapsing on its end date.

livemode boolean required

Which realm the event happened in. False is the sandbox.

mocked boolean required

Whether a mock produced this fact, rather than an engine computing it. Recorded on the event when it was appended and never worked out afterwards from the realm: the two answers agree while every module is on its mock and part on the day the first engine ships. See ADR-0011.

source string required

Which part of Heros is the authority for this fact: anchor (identity), proof (credentials), rail (engagements), flow (sourcing), match (allocation), run (payroll), remit (remittance), route (payouts), gateway (the API's front door), iam (accounts and API keys), ledger (the books), registry (rule packs), delivery (webhooks and messages), documents (rendered payslips and instruments) or intelligence (AI decisions). Read the fact from there when it matters; your own copy is never the authority.

anchorproofrailflowmatchrunremitroutegatewayiamledgerregistrydeliverydocumentsintelligence
object always "event" required

Always event. Tells you which kind of record you are looking at, so one handler can read any response.

stream string required

The id of the record the event is about: an instruction set (remit_authority_rail_instruction_…), obligation, leg, receipt or return (remit_authority_rail_return_…). sequence counts within it; replay with both at GET /v1/remittance/events.

data object required

The record the event is about, as it stood when the event happened. Its shape follows type: an instruction set, an obligation, a leg, a receipt or an employer return.

has_more boolean required

true when there are more records after this page. Pass the last record's id as starting_after to get the next page.

Other responses

400The request could not be read, or a value was refused.
401No valid credential was presented.
403The credential does not carry the required scope.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
# query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
curl -X GET "https://sandbox.droomwork.io/v1/remittance/events?stream=remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&after=0&limit=25" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

// query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
const result = await api.remittanceEventsList({ stream: 'remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', after: 0, limit: 25 });
// query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/events?stream=remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&after=0&limit=25', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

# query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
result = api.remittance_events_list(stream='remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', after=0, limit=25)
import os

import requests

# query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/events?stream=remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&after=0&limit=25',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

# query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
$result = $api->remittanceEventsList(stream: 'remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', after: 0, limit: 25);
<?php
// query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/events?stream=remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&after=0&limit=25');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

// query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
var result = api.remittanceEventsList("remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", 0, 25, null);
// query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/events?stream=remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&after=0&limit=25"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

// query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
var result = api.RemittanceEventsList(stream: "remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", after: 0, limit: 25);
// query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/events?stream=remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&after=0&limit=25");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

// query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
result, _, err := client.REMITAPI.RemittanceEventsList(ctx).Stream("remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").After(0).Limit(25).Execute()
// query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/events?stream=remit_authority_rail_instruction_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&after=0&limit=25", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "object": "list",
  "data": [
    {
      "id": "evt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "type": "run.payslip.calculated",
      "schema_version": 1,
      "org_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "sequence": 0,
      "occurred_at": "2026-09-01T09:00:00Z",
      "livemode": false,
      "mocked": true,
      "source": "anchor",
      "request_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "object": "event",
      "stream": "example",
      "data": {}
    }
  ],
  "has_more": true
}
GET/v1/remittance/events/{event_id}#

Look up one event you already logged

remittance.events.retrieve

An event identifier on its own becomes the whole record here: what happened, which remittance record it happened to, and that record's state at the time. The identifier never changes, so an event you logged once still shows that record as it stood then, after the record itself has moved on.

Send the event's id in the path. You get the event whole: its type, the stream it belongs to, its sequence in that stream, and data, the record the event is about.

Carry stream and sequence to GET /v1/remittance/events as stream and after to read what followed in that record's history. An event_id nothing holds answers not_found.

Path parameters

event_id string required

The event's identifier: the id on an event from GET /v1/remittance/events or on the body of a webhook delivery. It starts with evt_, and a redelivery carries the same one.

Returns

The event, with occurred_at, so your own log carries when it happened.

id string required

The event's identifier, starting with evt_, the same on a webhook delivery and on the module's events list, such as GET /v1/payroll/events. It never changes: a redelivery carries the same id, so you can recognise an event you have already handled.

type string required

What happened, as module.resource.past_tense_verb, for example run.payslip.calculated. Pick your handler on it; data takes the shape this type promises.

schema_version integer · minimum 1 required

The version of the shape data takes for this type, starting at 1. A change to the shape raises it, so check it before you read data.

org_id string required

The organisation the event belongs to, by its id, which starts with org_: the one POST /v1/registrations gave you and GET /v1/me returns. You only ever receive events for your own organisation.

sequence integer · minimum 0 required

Per organisation and per stream. It is how a consumer tells a replay from a new event, and it is what the delivery guarantee rests on.

occurred_at string · date-time required

When the event happened, as an RFC 3339 timestamp in UTC. Not when it was delivered: a redelivery carries the original value.

request_id string optional

The request that caused this event, where one did: the Droomwork-Request-Id that request returned, starting with req_. Absent for an event a schedule raised, such as an engagement lapsing on its end date.

livemode boolean required

Which realm the event happened in. False is the sandbox.

mocked boolean required

Whether a mock produced this fact, rather than an engine computing it. Recorded on the event when it was appended and never worked out afterwards from the realm: the two answers agree while every module is on its mock and part on the day the first engine ships. See ADR-0011.

source string required

Which part of Heros is the authority for this fact: anchor (identity), proof (credentials), rail (engagements), flow (sourcing), match (allocation), run (payroll), remit (remittance), route (payouts), gateway (the API's front door), iam (accounts and API keys), ledger (the books), registry (rule packs), delivery (webhooks and messages), documents (rendered payslips and instruments) or intelligence (AI decisions). Read the fact from there when it matters; your own copy is never the authority.

anchorproofrailflowmatchrunremitroutegatewayiamledgerregistrydeliverydocumentsintelligence
object always "event" required

Always event. Tells you which kind of record you are looking at, so one handler can read any response.

stream string required

The id of the record the event is about: an instruction set (remit_authority_rail_instruction_…), obligation, leg, receipt or return (remit_authority_rail_return_…). sequence counts within it; replay with both at GET /v1/remittance/events.

data object required

The record the event is about, as it stood when the event happened. Its shape follows type: an instruction set, an obligation, a leg, a receipt or an employer return.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X GET "https://sandbox.droomwork.io/v1/remittance/events/%7Bevent_id%7D" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceEventsRetrieve({ eventId: '{event_id}' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/events/%7Bevent_id%7D', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_events_retrieve(event_id='{event_id}')
import os

import requests

response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/events/%7Bevent_id%7D',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceEventsRetrieve(event_id: '{event_id}');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/events/%7Bevent_id%7D');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceEventsRetrieve("{event_id}");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/events/%7Bevent_id%7D"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceEventsRetrieve(eventId: "{event_id}");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/events/%7Bevent_id%7D");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceEventsRetrieve(ctx, "{event_id}").Execute()
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/events/%7Bevent_id%7D", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "evt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "type": "run.payslip.calculated",
  "schema_version": 1,
  "org_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "sequence": 0,
  "occurred_at": "2026-09-01T09:00:00Z",
  "livemode": false,
  "mocked": true,
  "source": "anchor",
  "request_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "event",
  "stream": "example",
  "data": {}
}
GET/v1/remittance/audit_entries#

Who approved or overrode what, and when

remittance.audit_entries.list

This is who did what in REMIT. Every attempt that changed something is recorded, and so is every one refused under a credential we recognised, so your product can name who approved a remittance or who overrode a discrepancy.

Send nothing, or narrow by action, actor, record, outcome or a window of time. You get a page of entries newest first, each naming who acted, what they attempted and the status they were given.

action matches exactly and holds the route pattern, not the URL you called, so read the value off an entry before you filter on it.

Your own successful reads leave no entry here, and nothing refused with unauthenticated is recorded, so a revoked credential's calls are not here either.

An entry never says what changed, or the reason behind a refusal. Read one in full at GET /v1/remittance/audit_entries/{audit_entry_id}.

Query parameters

action string optional

Restricts the list to attempts at one route, as action reads on an entry: the method and route pattern, such as POST /v1/remittance/returns. Leave it out to get attempts at every route.

actor_id string optional

Restricts the list to one credential, by the exact actor_id on its entries: the id of the API key (key_…) or staff account that made the attempt. Pair it with outcome=refused to see repeated refusals; leave it out to get every actor.

resource string optional

Restricts the list to attempts on one kind of record, as resource reads on an entry: the collection segment of the route, such as returns, remittances, legs or receipts. Leave it out to get every kind.

resource_id string optional

Restricts the list to attempts on one record, as resource_id reads on an entry: the identifier the route named, such as a return's id from POST /v1/remittance/returns (remit_authority_rail_return_…). Leave it out to get every record.

outcome string optional

Restricts the list to one outcome: succeeded, refused (a 4xx answer) or failed (a 5xx answer). refused is where to look for a credential being probed; leave it out to get every outcome.

succeededrefusedfailed
recorded_after string optional

Only entries recorded after this moment, as an RFC 3339 timestamp in UTC such as 2026-01-01T00:00:00Z; an entry at exactly this time is left out. Leave it out to read from the oldest entry.

recorded_before string optional

Only entries recorded before this moment, as an RFC 3339 timestamp in UTC such as 2027-01-01T00:00:00Z; an entry at exactly this time is left out. Pair it with recorded_after to read one window, or leave it out to read up to the newest.

limit integer optional

How many records to return on one page, from 1 to 100, and 25 if you leave it out. When has_more is true, pass the last record's id as starting_after to get the next page.

starting_after string optional

The id of the last record on the previous page of this same list. Leave it out to get the first page; when a page comes back with has_more true, send its last record's id here to get the page after it.

Returns

A page of audit entries.

object always "list" required

Always list. Tells you which kind of record you are looking at, so one handler can read any response.

data array of AuditEntry required

The records on this page, in the order the list promises. Empty when nothing matched.

13 fields of AuditEntry
id string required

The entry's identifier, on every entry from GET /v1/remittance/audit_entries. It starts with aud_ and never changes; pass it as audit_entry_id to GET /v1/remittance/audit_entries/{audit_entry_id} to retrieve one entry.

object always "audit_entry" required

Always audit_entry. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm the action happened in. False is the sandbox.

mocked boolean required

Whether the route this attempt was aimed at is mocked. It describes the route, not the answer: a refused attempt and a replayed idempotent request against a mocked route both record true. Recorded with the entry, not inferred from the realm beside it.

at string · date-time required

When the attempt was recorded, as an RFC 3339 timestamp in UTC. The list is ordered by it, newest first.

request_id string required

The request this attempt was made in: the Droomwork-Request-Id header on its response, and the request_id on any error body. Quote it when you ask us about one.

actor_type string required

What kind of credential made the attempt: client for an API key or OAuth client, user for a signed-in person, staff for a Heros staff member under a grant, service when Heros acted for you.

actor_id string required

The id of the credential that made the attempt, of the kind actor_type says: the API key's (key_…) for client, the staff account's for staff. Pass it as actor_id to GET /v1/remittance/audit_entries to follow one credential.

action string required

What was attempted, as the method and the route pattern.

resource string · nullable optional

The kind of record acted on, as the collection segment of the route, such as returns or legs. null when the route named none.

resource_id string · nullable optional

The id of the record the route named, such as a return's from POST /v1/remittance/returns (remit_authority_rail_return_…) on /v1/remittance/returns/{return_id}. null for an attempt on a collection, such as creating or listing.

outcome string required

How the attempt ended: succeeded (a status below 400), refused (a 4xx status) or failed (a 5xx status). status carries the exact code.

succeededrefusedfailed
status integer required

The HTTP status the caller was given, such as 201, 403 or 500. outcome follows it: below 400 is succeeded, 4xx is refused, 5xx is failed.

has_more boolean required

true when there are more records after this page. Pass the last record's id as starting_after to get the next page.

Other responses

400The request could not be read, or a value was refused.
401No valid credential was presented.
403The credential does not carry the required scope.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
# query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
curl -X GET "https://sandbox.droomwork.io/v1/remittance/audit_entries?action=POST%20%2Fv1%2Fremittance%2Freturns&actor_id=usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&resource=returns&resource_id=remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=succeeded&recorded_after=2026-01-01T00%3A00%3A00Z&recorded_before=2027-01-01T00%3A00%3A00Z&limit=25" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

// query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
const result = await api.remittanceAuditEntriesList({ action: 'POST /v1/remittance/returns', actorId: 'usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', resource: 'returns', resourceId: 'remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', outcome: 'succeeded', recordedAfter: '2026-01-01T00:00:00Z', recordedBefore: '2027-01-01T00:00:00Z', limit: 25 });
// query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/audit_entries?action=POST%20%2Fv1%2Fremittance%2Freturns&actor_id=usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&resource=returns&resource_id=remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=succeeded&recorded_after=2026-01-01T00%3A00%3A00Z&recorded_before=2027-01-01T00%3A00%3A00Z&limit=25', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

# query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
result = api.remittance_audit_entries_list(action='POST /v1/remittance/returns', actor_id='usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', resource='returns', resource_id='remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', outcome='succeeded', recorded_after='2026-01-01T00:00:00Z', recorded_before='2027-01-01T00:00:00Z', limit=25)
import os

import requests

# query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/audit_entries?action=POST%20%2Fv1%2Fremittance%2Freturns&actor_id=usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&resource=returns&resource_id=remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=succeeded&recorded_after=2026-01-01T00%3A00%3A00Z&recorded_before=2027-01-01T00%3A00%3A00Z&limit=25',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

# query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
$result = $api->remittanceAuditEntriesList(action: 'POST /v1/remittance/returns', actor_id: 'usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', resource: 'returns', resource_id: 'remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', outcome: 'succeeded', recorded_after: '2026-01-01T00:00:00Z', recorded_before: '2027-01-01T00:00:00Z', limit: 25);
<?php
// query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/audit_entries?action=POST%20%2Fv1%2Fremittance%2Freturns&actor_id=usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&resource=returns&resource_id=remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=succeeded&recorded_after=2026-01-01T00%3A00%3A00Z&recorded_before=2027-01-01T00%3A00%3A00Z&limit=25');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

// query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
var result = api.remittanceAuditEntriesList("POST /v1/remittance/returns", "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "returns", "remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "succeeded", "2026-01-01T00:00:00Z", "2027-01-01T00:00:00Z", 25, null);
// query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/audit_entries?action=POST%20%2Fv1%2Fremittance%2Freturns&actor_id=usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&resource=returns&resource_id=remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=succeeded&recorded_after=2026-01-01T00%3A00%3A00Z&recorded_before=2027-01-01T00%3A00%3A00Z&limit=25"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

// query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
var result = api.RemittanceAuditEntriesList(action: "POST /v1/remittance/returns", actorId: "usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", resource: "returns", resourceId: "remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", outcome: "succeeded", recordedAfter: "2026-01-01T00:00:00Z", recordedBefore: "2027-01-01T00:00:00Z", limit: 25);
// query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/audit_entries?action=POST%20%2Fv1%2Fremittance%2Freturns&actor_id=usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&resource=returns&resource_id=remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=succeeded&recorded_after=2026-01-01T00%3A00%3A00Z&recorded_before=2027-01-01T00%3A00%3A00Z&limit=25");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

// query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
result, _, err := client.REMITAPI.RemittanceAuditEntriesList(ctx).Action("POST /v1/remittance/returns").ActorId("usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Resource("returns").ResourceId("remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Outcome("succeeded").RecordedAfter("2026-01-01T00:00:00Z").RecordedBefore("2027-01-01T00:00:00Z").Limit(25).Execute()
// query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/audit_entries?action=POST%20%2Fv1%2Fremittance%2Freturns&actor_id=usr_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&resource=returns&resource_id=remit_authority_rail_return_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=succeeded&recorded_after=2026-01-01T00%3A00%3A00Z&recorded_before=2027-01-01T00%3A00%3A00Z&limit=25", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "object": "list",
  "data": [
    {
      "id": "aud_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "object": "audit_entry",
      "livemode": false,
      "mocked": true,
      "at": "2026-09-01T09:00:00Z",
      "request_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "actor_type": "example",
      "actor_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
      "action": "example",
      "outcome": "succeeded",
      "status": 1,
      "resource": "returns",
      "resource_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
    }
  ],
  "has_more": true
}
GET/v1/remittance/audit_entries/{audit_entry_id}#

Account for one attempt in full

remittance.audit_entries.retrieve

An audit entry is one attempt to change something, or one that was refused, and this reads one back. It names the credential behind the attempt and the exact status it was answered with, so an approval or an override can be traced to one actor and one moment.

Send the entry's id in the path. You get when the attempt was made, which credential made it, what it was aimed at, and how it ended.

An entry never says what changed, or the reason behind a refusal. For what happened to the record itself, read GET /v1/remittance/events.

Where resource_id is set, open that record, such as a return at GET /v1/remittance/returns/{return_id}. An audit_entry_id nothing holds answers not_found.

Path parameters

audit_entry_id string required

The entry's identifier: the id on an entry from GET /v1/remittance/audit_entries. It starts with aud_.

Returns

The audit entry.

id string required

The entry's identifier, on every entry from GET /v1/remittance/audit_entries. It starts with aud_ and never changes; pass it as audit_entry_id to GET /v1/remittance/audit_entries/{audit_entry_id} to retrieve one entry.

object always "audit_entry" required

Always audit_entry. Tells you which kind of record you are looking at, so one handler can read any response.

livemode boolean required

Which realm the action happened in. False is the sandbox.

mocked boolean required

Whether the route this attempt was aimed at is mocked. It describes the route, not the answer: a refused attempt and a replayed idempotent request against a mocked route both record true. Recorded with the entry, not inferred from the realm beside it.

at string · date-time required

When the attempt was recorded, as an RFC 3339 timestamp in UTC. The list is ordered by it, newest first.

request_id string required

The request this attempt was made in: the Droomwork-Request-Id header on its response, and the request_id on any error body. Quote it when you ask us about one.

actor_type string required

What kind of credential made the attempt: client for an API key or OAuth client, user for a signed-in person, staff for a Heros staff member under a grant, service when Heros acted for you.

actor_id string required

The id of the credential that made the attempt, of the kind actor_type says: the API key's (key_…) for client, the staff account's for staff. Pass it as actor_id to GET /v1/remittance/audit_entries to follow one credential.

action string required

What was attempted, as the method and the route pattern.

resource string · nullable optional

The kind of record acted on, as the collection segment of the route, such as returns or legs. null when the route named none.

resource_id string · nullable optional

The id of the record the route named, such as a return's from POST /v1/remittance/returns (remit_authority_rail_return_…) on /v1/remittance/returns/{return_id}. null for an attempt on a collection, such as creating or listing.

outcome string required

How the attempt ended: succeeded (a status below 400), refused (a 4xx status) or failed (a 5xx status). status carries the exact code.

succeededrefusedfailed
status integer required

The HTTP status the caller was given, such as 201, 403 or 500. outcome follows it: below 400 is succeeded, 4xx is refused, 5xx is failed.

Other responses

401No valid credential was presented.
403The credential does not carry the required scope.
404No record with that identifier.

Errors it can return

Sends against https://sandbox.droomwork.io
Request
which?
curl -X GET "https://sandbox.droomwork.io/v1/remittance/audit_entries/%7Baudit_entry_id%7D" \
  -H "Droomwork-Api-Key: $DROOMWORK_API_KEY"
import { Configuration, REMITApi } from '@heros/sdk';

const api = new REMITApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));

const result = await api.remittanceAuditEntriesRetrieve({ auditEntryId: '{audit_entry_id}' });
const response = await fetch('https://sandbox.droomwork.io/v1/remittance/audit_entries/%7Baudit_entry_id%7D', {
  method: 'GET',
  headers: {
    'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
  },
});
const result = await response.json();
import os

import heros_sdk

config = heros_sdk.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = heros_sdk.ApiClient(config)
api = heros_sdk.REMITApi(client)

result = api.remittance_audit_entries_retrieve(audit_entry_id='{audit_entry_id}')
import os

import requests

response = requests.request(
    'GET',
    'https://sandbox.droomwork.io/v1/remittance/audit_entries/%7Baudit_entry_id%7D',
    headers={
        'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
    },
)
result = response.json()
<?php
require_once __DIR__ . '/vendor/autoload.php';

$config = HerosSdk\Configuration::getDefaultConfiguration()
  ->setHost('https://sandbox.droomwork.io')
  ->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new HerosSdk\Api\REMITApi(new GuzzleHttp\Client(), $config);

$result = $api->remittanceAuditEntriesRetrieve(audit_entry_id: '{audit_entry_id}');
<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/remittance/audit_entries/%7Baudit_entry_id%7D');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_HTTPHEADER => [
    'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
  ],
]);
$result = json_decode(curl_exec($ch), true);
import com.useheros.sdk.ApiClient;
import com.useheros.sdk.Configuration;
import com.useheros.sdk.api.RemitApi;

ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
RemitApi api = new RemitApi(client);

var result = api.remittanceAuditEntriesRetrieve("{audit_entry_id}");
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/remittance/audit_entries/%7Baudit_entry_id%7D"))
    .header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();
using Heros.Sdk.Api;
using Heros.Sdk.Client;

var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new REMITApi(config);

var result = api.RemittanceAuditEntriesRetrieve(auditEntryId: "{audit_entry_id}");
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/remittance/audit_entries/%7Baudit_entry_id%7D");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();
import heros "github.com/fenibofubara/heros-sdk-go"

ctx := context.WithValue(context.Background(), heros.ContextAPIKeys, map[string]heros.APIKey{
	"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := heros.NewConfiguration()
cfg.Servers = heros.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := heros.NewAPIClient(cfg)

result, _, err := client.REMITAPI.RemittanceAuditEntriesRetrieve(ctx, "{audit_entry_id}").Execute()
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/remittance/audit_entries/%7Baudit_entry_id%7D", nil)
	req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
Response
{
  "id": "aud_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "object": "audit_entry",
  "livemode": false,
  "mocked": true,
  "at": "2026-09-01T09:00:00Z",
  "request_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "actor_type": "example",
  "actor_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
  "action": "example",
  "outcome": "succeeded",
  "status": 1,
  "resource": "returns",
  "resource_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
}